grpc-0.11.1/0000755000175000017500000000000012600663511012717 5ustar apollockapollockgrpc-0.11.1/README.md0000644000175000017500000001260012600663151014175 0ustar apollockapollock[![Build Status](https://grpc-testing.appspot.com/job/gRPC_master/badge/icon)](https://grpc-testing.appspot.com/job/gRPC_master) [![Coverage Status](https://img.shields.io/coveralls/grpc/grpc.svg)](https://coveralls.io/r/grpc/grpc?branch=master) [gRPC - An RPC library and framework](http://github.com/grpc/grpc) =================================== Copyright 2015 Google Inc. #Documentation You can find more detailed documentation and examples in the [doc](doc) and [examples](examples) directories respectively. #Installation See grpc/INSTALL for installation instructions for various platforms. #Repository Structure This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core] (src/core). * C++ source code: [src/cpp] (src/cpp) * Ruby source code: [src/ruby] (src/ruby) * NodeJS source code: [src/node] (src/node) * Python source code: [src/python] (src/python) * PHP source code: [src/php] (src/php) * C# source code: [src/csharp] (src/csharp) * Objective-C source code: [src/objective-c] (src/objective-c) Java source code is in [grpc-java] (http://github.com/grpc/grpc-java) repository. Go source code is in [grpc-go] (http://github.com/grpc/grpc-go) repository. #Current Status of libraries Libraries in different languages are in different state of development. We are seeking contributions for all of these libraries. * shared C core library [src/core] (src/core) : Early adopter ready - Alpha. * C++ Library: [src/cpp] (src/cpp) : Early adopter ready - Alpha. * Ruby Library: [src/ruby] (src/ruby) : Early adopter ready - Alpha. * NodeJS Library: [src/node] (src/node) : Early adopter ready - Alpha. * Python Library: [src/python] (src/python) : Early adopter ready - Alpha. * C# Library: [src/csharp] (src/csharp) : Early adopter ready - Alpha. * Objective-C Library: [src/objective-c] (src/objective-c): Early adopter ready - Alpha. * PHP Library: [src/php] (src/php) : Pre-Alpha. #Overview Remote Procedure Calls (RPCs) provide a useful abstraction for building distributed applications and services. The libraries in this repository provide a concrete implementation of the gRPC protocol, layered over HTTP/2. These libraries enable communication between clients and servers using any combination of the supported languages. ##Interface Developers using gRPC typically start with the description of an RPC service (a collection of methods), and generate client and server side interfaces which they use on the client-side and implement on the server side. By default, gRPC uses [Protocol Buffers](https://github.com/google/protobuf) as the Interface Definition Language (IDL) for describing both the service interface and the structure of the payload messages. It is possible to use other alternatives if desired. ###Surface API Starting from an interface definition in a .proto file, gRPC provides Protocol Compiler plugins that generate Client- and Server-side APIs. gRPC users typically call into these APIs on the Client side and implement the corresponding API on the server side. #### Synchronous vs. asynchronous Synchronous RPC calls, that block until a response arrives from the server, are the closest approximation to the abstraction of a procedure call that RPC aspires to. On the other hand, networks are inherently asynchronous and in many scenarios, it is desirable to have the ability to start RPCs without blocking the current thread. The gRPC programming surface in most languages comes in both synchronous and asynchronous flavors. ## Streaming gRPC supports streaming semantics, where either the client or the server (or both) send a stream of messages on a single RPC call. The most general case is Bidirectional Streaming where a single gRPC call establishes a stream where both the client and the server can send a stream of messages to each other. The streamed messages are delivered in the order they were sent. #Protocol The [gRPC protocol](doc/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between clients and servers. A concrete embedding over HTTP/2 completes the picture by fleshing out the details of each of the required operations. ## Abstract gRPC protocol A gRPC RPC comprises of a bidirectional stream of messages, initiated by the client. In the client-to-server direction, this stream begins with a mandatory `Call Header`, followed by optional `Initial-Metadata`, followed by zero or more `Payload Messages`. The server-to-client direction contains an optional `Initial-Metadata`, followed by zero or more `Payload Messages` terminated with a mandatory `Status` and optional `Status-Metadata` (a.k.a.,`Trailing-Metadata`). ## Implementation over HTTP/2 The abstract protocol defined above is implemented over [HTTP/2](https://http2.github.io/). gRPC bidirectional streams are mapped to HTTP/2 streams. The contents of `Call Header` and `Initial Metadata` are sent as HTTP/2 headers and subject to HPACK compression. `Payload Messages` are serialized into a byte stream of length prefixed gRPC frames which are then fragmented into HTTP/2 frames at the sender and reassembled at the receiver. `Status` and `Trailing-Metadata` are sent as HTTP/2 trailing headers (a.k.a., trailers). ## Flow Control gRPC inherits the flow control mechanisms in HTTP/2 and uses them to enable fine-grained control of the amount of memory used for buffering in-flight messages. grpc-0.11.1/src/0000755000175000017500000000000012600663151013506 5ustar apollockapollockgrpc-0.11.1/src/node/0000755000175000017500000000000012600663151014433 5ustar apollockapollockgrpc-0.11.1/src/node/package.json0000644000175000017500000000246212600663151016725 0ustar apollockapollock{ "name": "grpc", "version": "0.11.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", "repository": { "type": "git", "url": "https://github.com/grpc/grpc.git" }, "bugs": "https://github.com/grpc/grpc/issues", "contributors": [ { "name": "Michael Lumish", "email": "mlumish@google.com" } ], "directories": { "lib": "src", "example": "examples" }, "scripts": { "lint": "node ./node_modules/jshint/bin/jshint src test examples interop index.js", "test": "node ./node_modules/mocha/bin/mocha && npm run-script lint", "gen_docs": "./node_modules/.bin/jsdoc -c jsdoc_conf.json" }, "dependencies": { "bindings": "^1.2.0", "lodash": "^3.9.3", "nan": "^2.0.0", "protobufjs": "^4.0.0" }, "devDependencies": { "async": "^0.9.0", "google-auth-library": "^0.9.2", "jsdoc": "^3.3.2", "jshint": "^2.5.0", "minimist": "^1.1.0", "mocha": "~1.21.0", "mustache": "^2.0.0", "strftime": "^0.8.2" }, "engines": { "node": ">=0.10.13" }, "files": [ "LICENSE", "README.md", "index.js", "binding.gyp", "bin", "cli", "examples", "ext", "interop", "src", "test" ], "main": "index.js", "license": "BSD-3-Clause" } grpc-0.11.1/src/node/README.md0000644000175000017500000000667612600663151015731 0ustar apollockapollock# Node.js gRPC Library ## Status Beta ## PREREQUISITES - `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. - [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core. ## INSTALLATION **Linux (Debian):** Add [Debian jessie-backports][] to your `sources.list` file. Example: ```sh echo "deb http://http.debian.net/debian jessie-backports main" | \ sudo tee -a /etc/apt/sources.list ``` Install the gRPC Debian package ```sh sudo apt-get update sudo apt-get install libgrpc-dev ``` Install the gRPC NPM package ```sh npm install grpc ``` **Mac OS X** Install [homebrew][]. Run the following command to install gRPC Node.js. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s nodejs ``` This will download and run the [gRPC install script][], then install the latest version of gRPC Nodejs npm package. ## BUILD FROM SOURCE 1. Clone [the grpc Git Repository](https://github.com/grpc/grpc). 2. Follow the instructions in the `INSTALL` file in the root of that repository to install the C core library that this package depends on. 3. Run `npm install`. If you install the gRPC C core library in a custom location, then you need to set some environment variables to install this library. The command will look like this: ```sh CXXFLAGS=-I/include LDFLAGS=-L/lib npm install [grpc] ``` ## TESTING To run the test suite, simply run `npm test` in the install location. ## API This library internally uses [ProtoBuf.js](https://github.com/dcodeIO/ProtoBuf.js), and some structures it exports match those exported by that library If you require this module, you will get an object with the following members ```javascript function load(filename) ``` Takes a filename of a [Protocol Buffer](https://developers.google.com/protocol-buffers/) file, and returns an object representing the structure of the protocol buffer in the following way: - Namespaces become maps from the names of their direct members to those member objects - Service definitions become client constructors for clients for that service. They also have a `service` member that can be used for constructing servers. - Message definitions become Message constructors like those that ProtoBuf.js would create - Enum definitions become Enum objects like those that ProtoBuf.js would create - Anything else becomes the relevant reflection object that ProtoBuf.js would create ```javascript function loadObject(reflectionObject) ``` Returns the same structure that `load` returns, but takes a reflection object from `ProtoBuf.js` instead of a file name. ```javascript function Server([serverOpions]) ``` Constructs a server to which service/implementation pairs can be added. ```javascript status ``` An object mapping status names to status code numbers. ```javascript callError ``` An object mapping call error names to codes. This is primarily useful for tracking down certain kinds of internal errors. ```javascript Credentials ``` An object with factory methods for creating credential objects for clients. ```javascript ServerCredentials ``` An object with factory methods for creating credential objects for servers. [homebrew]:http://brew.sh [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [Debian jessie-backports]:http://backports.debian.org/Instructions/ grpc-0.11.1/src/node/.jshintrc0000644000175000017500000000076012600663151016263 0ustar apollockapollock{ "bitwise": true, "curly": true, "eqeqeq": true, "esnext": true, "freeze": true, "immed": true, "indent": 2, "latedef": "nofunc", "maxlen": 80, "newcap": true, "node": true, "noarg": true, "quotmark": "single", "strict": true, "trailing": true, "undef": true, "unused": "vars", "globals": { /* Mocha-provided globals */ "describe": false, "it": false, "before": false, "beforeEach": false, "after": false, "afterEach": false } } grpc-0.11.1/src/node/src/0000755000175000017500000000000012600663151015222 5ustar apollockapollockgrpc-0.11.1/src/node/src/common.js0000644000175000017500000001147612600663151017061 0ustar apollockapollock/* * * 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. * */ /** * @module */ 'use strict'; var _ = require('lodash'); /** * Get a function that deserializes a specific type of protobuf. * @param {function()} cls The constructor of the message type to deserialize * @return {function(Buffer):cls} The deserialization function */ exports.deserializeCls = function deserializeCls(cls) { /** * Deserialize a buffer to a message object * @param {Buffer} arg_buf The buffer to deserialize * @return {cls} The resulting object */ return function deserialize(arg_buf) { // Convert to a native object with binary fields as Buffers (first argument) // and longs as strings (second argument) return cls.decode(arg_buf).toRaw(false, true); }; }; var deserializeCls = exports.deserializeCls; /** * Get a function that serializes objects to a buffer by protobuf class. * @param {function()} Cls The constructor of the message type to serialize * @return {function(Cls):Buffer} The serialization function */ exports.serializeCls = function serializeCls(Cls) { /** * Serialize an object to a Buffer * @param {Object} arg The object to serialize * @return {Buffer} The serialized object */ return function serialize(arg) { return new Buffer(new Cls(arg).encode().toBuffer()); }; }; var serializeCls = exports.serializeCls; /** * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of * @return {string} The fully qualified name of the value */ exports.fullyQualifiedName = function fullyQualifiedName(value) { if (value === null || value === undefined) { return ''; } var name = value.name; if (value.className === 'Service.RPCMethod') { name = _.capitalize(name); } if (value.hasOwnProperty('parent')) { var parent_name = fullyQualifiedName(value.parent); if (parent_name !== '') { name = parent_name + '.' + name; } } return name; }; var fullyQualifiedName = exports.fullyQualifiedName; /** * Wrap a function to pass null-like values through without calling it. If no * function is given, just uses the identity; * @param {?function} func The function to wrap * @return {function} The wrapped function */ exports.wrapIgnoreNull = function wrapIgnoreNull(func) { if (!func) { return _.identity; } return function(arg) { if (arg === null || arg === undefined) { return null; } return func(arg); }; }; /** * Return a map from method names to method attributes for the service. * @param {ProtoBuf.Reflect.Service} service The service to get attributes for * @return {Object} The attributes map */ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service) { var prefix = '/' + fullyQualifiedName(service) + '/'; return _.object(_.map(service.children, function(method) { return [_.camelCase(method.name), { path: prefix + _.capitalize(method.name), requestStream: method.requestStream, responseStream: method.responseStream, requestSerialize: serializeCls(method.resolvedRequestType.build()), requestDeserialize: deserializeCls(method.resolvedRequestType.build()), responseSerialize: serializeCls(method.resolvedResponseType.build()), responseDeserialize: deserializeCls(method.resolvedResponseType.build()) }]; })); }; grpc-0.11.1/src/node/src/metadata.js0000644000175000017500000001277712600663151017356 0ustar apollockapollock/* * * 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. * */ /** * Metadata module * @module */ 'use strict'; var _ = require('lodash'); /** * Class for storing metadata. Keys are normalized to lowercase ASCII. * @constructor */ function Metadata() { this._internal_repr = {}; } function normalizeKey(key) { if (!(/^[A-Za-z\d_-]+$/.test(key))) { throw new Error('Metadata keys must be nonempty strings containing only ' + 'alphanumeric characters and hyphens'); } return key.toLowerCase(); } function validate(key, value) { if (_.endsWith(key, '-bin')) { if (!(value instanceof Buffer)) { throw new Error('keys that end with \'-bin\' must have Buffer values'); } } else { if (!_.isString(value)) { throw new Error( 'keys that don\'t end with \'-bin\' must have String values'); } if (!(/^[\x20-\x7E]*$/.test(value))) { throw new Error('Metadata string values can only contain printable ' + 'ASCII characters and space'); } } } /** * Sets the given value for the given key, replacing any other values associated * with that key. Normalizes the key. * @param {String} key The key to set * @param {String|Buffer} value The value to set. Must be a buffer if and only * if the normalized key ends with '-bin' */ Metadata.prototype.set = function(key, value) { key = normalizeKey(key); validate(key, value); this._internal_repr[key] = [value]; }; /** * Adds the given value for the given key. Normalizes the key. * @param {String} key The key to add to. * @param {String|Buffer} value The value to add. Must be a buffer if and only * if the normalized key ends with '-bin' */ Metadata.prototype.add = function(key, value) { key = normalizeKey(key); validate(key, value); if (!this._internal_repr[key]) { this._internal_repr[key] = []; } this._internal_repr[key].push(value); }; /** * Remove the given key and any associated values. Normalizes the key. * @param {String} key The key to remove */ Metadata.prototype.remove = function(key) { key = normalizeKey(key); if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) { delete this._internal_repr[key]; } }; /** * Gets a list of all values associated with the key. Normalizes the key. * @param {String} key The key to get * @return {Array.} The values associated with that key */ Metadata.prototype.get = function(key) { key = normalizeKey(key); if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) { return this._internal_repr[key]; } else { return []; } }; /** * Get a map of each key to a single associated value. This reflects the most * common way that people will want to see metadata. * @return {Object.} A key/value mapping of the metadata */ Metadata.prototype.getMap = function() { var result = {}; _.forOwn(this._internal_repr, function(values, key) { if(values.length > 0) { result[key] = values[0]; } }); return result; }; /** * Clone the metadata object. * @return {Metadata} The new cloned object */ Metadata.prototype.clone = function() { var copy = new Metadata(); _.forOwn(this._internal_repr, function(value, key) { copy._internal_repr[key] = _.clone(value); }); return copy; }; /** * Gets the metadata in the format used by interal code. Intended for internal * use only. API stability is not guaranteed. * @private * @return {Object.>} The metadata */ Metadata.prototype._getCoreRepresentation = function() { return this._internal_repr; }; /** * Creates a Metadata object from a metadata map in the internal format. * Intended for internal use only. API stability is not guaranteed. * @private * @param {Object.>} The metadata * @return {Metadata} The new Metadata object */ Metadata._fromCoreRepresentation = function(metadata) { var newMetadata = new Metadata(); if (metadata) { newMetadata._internal_repr = _.cloneDeep(metadata); } return newMetadata; }; module.exports = Metadata; grpc-0.11.1/src/node/src/client.js0000644000175000017500000006202512600663151017043 0ustar apollockapollock/* * * 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. * */ /** * Client module * @module */ 'use strict'; var _ = require('lodash'); var grpc = require('bindings')('grpc.node'); var common = require('./common'); var Metadata = require('./metadata'); var EventEmitter = require('events').EventEmitter; var stream = require('stream'); var Readable = stream.Readable; var Writable = stream.Writable; var Duplex = stream.Duplex; var util = require('util'); var version = require('../package.json').version; util.inherits(ClientWritableStream, Writable); /** * A stream that the client can write to. Used for calls that are streaming from * the client side. * @constructor * @param {grpc.Call} call The call object to send data with * @param {function(*):Buffer=} serialize Serialization function for writes. */ function ClientWritableStream(call, serialize) { Writable.call(this, {objectMode: true}); this.call = call; this.serialize = common.wrapIgnoreNull(serialize); this.on('finish', function() { var batch = {}; batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; call.startBatch(batch, function() {}); }); } /** * Attempt to write the given chunk. Calls the callback when done. This is an * implementation of a method needed for implementing stream.Writable. * @access private * @param {Buffer} chunk The chunk to write * @param {string} encoding Used to pass write flags * @param {function(Error=)} callback Called when the write is complete */ function _write(chunk, encoding, callback) { /* jshint validthis: true */ var batch = {}; var message = this.serialize(chunk); if (_.isFinite(encoding)) { /* Attach the encoding if it is a finite number. This is the closest we * can get to checking that it is valid flags */ message.grpcWriteFlags = encoding; } batch[grpc.opType.SEND_MESSAGE] = message; this.call.startBatch(batch, function(err, event) { if (err) { // Something has gone wrong. Stop writing by failing to call callback return; } callback(); }); } ClientWritableStream.prototype._write = _write; util.inherits(ClientReadableStream, Readable); /** * A stream that the client can read from. Used for calls that are streaming * from the server side. * @constructor * @param {grpc.Call} call The call object to read data with * @param {function(Buffer):*=} deserialize Deserialization function for reads */ function ClientReadableStream(call, deserialize) { Readable.call(this, {objectMode: true}); this.call = call; this.finished = false; this.reading = false; this.deserialize = common.wrapIgnoreNull(deserialize); } /** * Read the next object from the stream. * @access private * @param {*} size Ignored because we use objectMode=true */ function _read(size) { /* jshint validthis: true */ var self = this; /** * Callback to be called when a READ event is received. Pushes the data onto * the read queue and starts reading again if applicable * @param {grpc.Event} event READ event object */ function readCallback(err, event) { if (err) { // Something has gone wrong. Stop reading and wait for status self.finished = true; return; } var data = event.read; var deserialized; try { deserialized = self.deserialize(data); } catch (e) { self.call.cancelWithStatus(grpc.status.INTERNAL, 'Failed to parse server response'); } if (self.push(deserialized) && data !== null) { var read_batch = {}; read_batch[grpc.opType.RECV_MESSAGE] = true; self.call.startBatch(read_batch, readCallback); } else { self.reading = false; } } if (self.finished) { self.push(null); } else { if (!self.reading) { self.reading = true; var read_batch = {}; read_batch[grpc.opType.RECV_MESSAGE] = true; self.call.startBatch(read_batch, readCallback); } } } ClientReadableStream.prototype._read = _read; util.inherits(ClientDuplexStream, Duplex); /** * A stream that the client can read from or write to. Used for calls with * duplex streaming. * @constructor * @param {grpc.Call} call Call object to proxy * @param {function(*):Buffer=} serialize Serialization function for requests * @param {function(Buffer):*=} deserialize Deserialization function for * responses */ function ClientDuplexStream(call, serialize, deserialize) { Duplex.call(this, {objectMode: true}); this.serialize = common.wrapIgnoreNull(serialize); this.deserialize = common.wrapIgnoreNull(deserialize); this.call = call; this.on('finish', function() { var batch = {}; batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; call.startBatch(batch, function() {}); }); } ClientDuplexStream.prototype._read = _read; ClientDuplexStream.prototype._write = _write; /** * Cancel the ongoing call */ function cancel() { /* jshint validthis: true */ this.call.cancel(); } ClientReadableStream.prototype.cancel = cancel; ClientWritableStream.prototype.cancel = cancel; ClientDuplexStream.prototype.cancel = cancel; /** * Get the endpoint this call/stream is connected to. * @return {string} The URI of the endpoint */ function getPeer() { /* jshint validthis: true */ return this.call.getPeer(); } ClientReadableStream.prototype.getPeer = getPeer; ClientWritableStream.prototype.getPeer = getPeer; ClientDuplexStream.prototype.getPeer = getPeer; /** * Get a call object built with the provided options. Keys for options are * 'deadline', which takes a date or number, and 'host', which takes a string * and overrides the hostname to connect to. * @param {Object} options Options map. */ function getCall(channel, method, options) { var deadline; var host; var parent; var propagate_flags; if (options) { deadline = options.deadline; host = options.host; parent = _.get(options, 'parent.call'); propagate_flags = options.propagate_flags; } if (deadline === undefined) { deadline = Infinity; } return new grpc.Call(channel, method, deadline, host, parent, propagate_flags); } /** * Get a function that can make unary requests to the specified method. * @param {string} method The name of the method to request * @param {function(*):Buffer} serialize The serialization function for inputs * @param {function(Buffer)} deserialize The deserialization function for * outputs * @return {Function} makeUnaryRequest */ function makeUnaryRequestFunction(method, serialize, deserialize) { /** * Make a unary request with this method on the given channel with the given * argument, callback, etc. * @this {Client} Client object. Must have a channel member. * @param {*} argument The argument to the call. Should be serializable with * serialize * @param {function(?Error, value=)} callback The callback to for when the * response is received * @param {Metadata=} metadata Metadata to add to the call * @param {Object=} options Options map * @return {EventEmitter} An event emitter for stream related events */ function makeUnaryRequest(argument, callback, metadata, options) { /* jshint validthis: true */ var emitter = new EventEmitter(); var call = getCall(this.$channel, method, options); if (metadata === null || metadata === undefined) { metadata = new Metadata(); } else { metadata = metadata.clone(); } emitter.cancel = function cancel() { call.cancel(); }; emitter.getPeer = function getPeer() { return call.getPeer(); }; this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) { if (error) { call.cancel(); callback(error); return; } var client_batch = {}; var message = serialize(argument); if (options) { message.grpcWriteFlags = options.flags; } client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata._getCoreRepresentation(); client_batch[grpc.opType.SEND_MESSAGE] = message; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_MESSAGE] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(client_batch, function(err, response) { response.status.metadata = Metadata._fromCoreRepresentation( response.status.metadata); var status = response.status; var error; var deserialized; if (status.code === grpc.status.OK) { if (err) { // Got a batch error, but OK status. Something went wrong callback(err); return; } else { try { deserialized = deserialize(response.read); } catch (e) { /* Change status to indicate bad server response. This will result * in passing an error to the callback */ status = { code: grpc.status.INTERNAL, details: 'Failed to parse server response' }; } } } if (status.code !== grpc.status.OK) { error = new Error(response.status.details); error.code = status.code; error.metadata = status.metadata; callback(error); } else { callback(null, deserialized); } emitter.emit('status', status); emitter.emit('metadata', Metadata._fromCoreRepresentation( response.metadata)); }); }); return emitter; } return makeUnaryRequest; } /** * Get a function that can make client stream requests to the specified method. * @param {string} method The name of the method to request * @param {function(*):Buffer} serialize The serialization function for inputs * @param {function(Buffer)} deserialize The deserialization function for * outputs * @return {Function} makeClientStreamRequest */ function makeClientStreamRequestFunction(method, serialize, deserialize) { /** * Make a client stream request with this method on the given channel with the * given callback, etc. * @this {Client} Client object. Must have a channel member. * @param {function(?Error, value=)} callback The callback to for when the * response is received * @param {Metadata=} metadata Array of metadata key/value pairs to add to the * call * @param {Object=} options Options map * @return {EventEmitter} An event emitter for stream related events */ function makeClientStreamRequest(callback, metadata, options) { /* jshint validthis: true */ var call = getCall(this.$channel, method, options); if (metadata === null || metadata === undefined) { metadata = new Metadata(); } else { metadata = metadata.clone(); } var stream = new ClientWritableStream(call, serialize); this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) { if (error) { call.cancel(); callback(error); return; } var metadata_batch = {}; metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata._getCoreRepresentation(); metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true; call.startBatch(metadata_batch, function(err, response) { if (err) { // The call has stopped for some reason. A non-OK status will arrive // in the other batch. return; } stream.emit('metadata', Metadata._fromCoreRepresentation( response.metadata)); }); var client_batch = {}; client_batch[grpc.opType.RECV_MESSAGE] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(client_batch, function(err, response) { response.status.metadata = Metadata._fromCoreRepresentation( response.status.metadata); var status = response.status; var error; var deserialized; if (status.code === grpc.status.OK) { if (err) { // Got a batch error, but OK status. Something went wrong callback(err); return; } else { try { deserialized = deserialize(response.read); } catch (e) { /* Change status to indicate bad server response. This will result * in passing an error to the callback */ status = { code: grpc.status.INTERNAL, details: 'Failed to parse server response' }; } } } if (status.code !== grpc.status.OK) { error = new Error(response.status.details); error.code = status.code; error.metadata = status.metadata; callback(error); } else { callback(null, deserialized); } stream.emit('status', status); }); }); return stream; } return makeClientStreamRequest; } /** * Get a function that can make server stream requests to the specified method. * @param {string} method The name of the method to request * @param {function(*):Buffer} serialize The serialization function for inputs * @param {function(Buffer)} deserialize The deserialization function for * outputs * @return {Function} makeServerStreamRequest */ function makeServerStreamRequestFunction(method, serialize, deserialize) { /** * Make a server stream request with this method on the given channel with the * given argument, etc. * @this {SurfaceClient} Client object. Must have a channel member. * @param {*} argument The argument to the call. Should be serializable with * serialize * @param {Metadata=} metadata Array of metadata key/value pairs to add to the * call * @param {Object} options Options map * @return {EventEmitter} An event emitter for stream related events */ function makeServerStreamRequest(argument, metadata, options) { /* jshint validthis: true */ var call = getCall(this.$channel, method, options); if (metadata === null || metadata === undefined) { metadata = new Metadata(); } else { metadata = metadata.clone(); } var stream = new ClientReadableStream(call, deserialize); this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) { if (error) { call.cancel(); stream.emit('error', error); return; } var start_batch = {}; var message = serialize(argument); if (options) { message.grpcWriteFlags = options.flags; } start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata._getCoreRepresentation(); start_batch[grpc.opType.RECV_INITIAL_METADATA] = true; start_batch[grpc.opType.SEND_MESSAGE] = message; start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; call.startBatch(start_batch, function(err, response) { if (err) { // The call has stopped for some reason. A non-OK status will arrive // in the other batch. return; } stream.emit('metadata', Metadata._fromCoreRepresentation( response.metadata)); }); var status_batch = {}; status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(status_batch, function(err, response) { response.status.metadata = Metadata._fromCoreRepresentation( response.status.metadata); stream.emit('status', response.status); if (response.status.code !== grpc.status.OK) { var error = new Error(response.status.details); error.code = response.status.code; error.metadata = response.status.metadata; stream.emit('error', error); return; } else { if (err) { // Got a batch error, but OK status. Something went wrong stream.emit('error', err); return; } } }); }); return stream; } return makeServerStreamRequest; } /** * Get a function that can make bidirectional stream requests to the specified * method. * @param {string} method The name of the method to request * @param {function(*):Buffer} serialize The serialization function for inputs * @param {function(Buffer)} deserialize The deserialization function for * outputs * @return {Function} makeBidiStreamRequest */ function makeBidiStreamRequestFunction(method, serialize, deserialize) { /** * Make a bidirectional stream request with this method on the given channel. * @this {SurfaceClient} Client object. Must have a channel member. * @param {Metadata=} metadata Array of metadata key/value pairs to add to the * call * @param {Options} options Options map * @return {EventEmitter} An event emitter for stream related events */ function makeBidiStreamRequest(metadata, options) { /* jshint validthis: true */ var call = getCall(this.$channel, method, options); if (metadata === null || metadata === undefined) { metadata = new Metadata(); } else { metadata = metadata.clone(); } var stream = new ClientDuplexStream(call, serialize, deserialize); this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) { if (error) { call.cancel(); stream.emit('error', error); return; } var start_batch = {}; start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata._getCoreRepresentation(); start_batch[grpc.opType.RECV_INITIAL_METADATA] = true; call.startBatch(start_batch, function(err, response) { if (err) { // The call has stopped for some reason. A non-OK status will arrive // in the other batch. return; } stream.emit('metadata', Metadata._fromCoreRepresentation( response.metadata)); }); var status_batch = {}; status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(status_batch, function(err, response) { response.status.metadata = Metadata._fromCoreRepresentation( response.status.metadata); stream.emit('status', response.status); if (response.status.code !== grpc.status.OK) { var error = new Error(response.status.details); error.code = response.status.code; error.metadata = response.status.metadata; stream.emit('error', error); return; } else { if (err) { // Got a batch error, but OK status. Something went wrong stream.emit('error', err); return; } } }); }); return stream; } return makeBidiStreamRequest; } /** * Map with short names for each of the requester maker functions. Used in * makeClientConstructor */ var requester_makers = { unary: makeUnaryRequestFunction, server_stream: makeServerStreamRequestFunction, client_stream: makeClientStreamRequestFunction, bidi: makeBidiStreamRequestFunction }; /** * Creates a constructor for a client with the given methods. The methods object * maps method name to an object with the following keys: * path: The path on the server for accessing the method. For example, for * protocol buffers, we use "/service_name/method_name" * requestStream: bool indicating whether the client sends a stream * resonseStream: bool indicating whether the server sends a stream * requestSerialize: function to serialize request objects * responseDeserialize: function to deserialize response objects * @param {Object} methods An object mapping method names to method attributes * @param {string} serviceName The fully qualified name of the service * @return {function(string, Object)} New client constructor */ exports.makeClientConstructor = function(methods, serviceName) { /** * Create a client with the given methods * @constructor * @param {string} address The address of the server to connect to * @param {grpc.Credentials} credentials Credentials to use to connect * to the server * @param {Object} options Options to pass to the underlying channel * @param {function(string, Object, function)=} updateMetadata function to * update the metadata for each request */ function Client(address, credentials, options, updateMetadata) { if (!updateMetadata) { updateMetadata = function(uri, metadata, callback) { callback(null, metadata); }; } if (!options) { options = {}; } options['grpc.primary_user_agent'] = 'grpc-node/' + version; /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ this.$channel = new grpc.Channel(address, credentials, options); // Remove the optional DNS scheme, trailing port, and trailing backslash address = address.replace(/^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$/, '$2'); this.$server_address = address; this.$auth_uri = 'https://' + this.$server_address + '/' + serviceName; this.$updateMetadata = updateMetadata; } _.each(methods, function(attrs, name) { var method_type; if (_.startsWith(name, '$')) { throw new Error('Method names cannot start with $'); } if (attrs.requestStream) { if (attrs.responseStream) { method_type = 'bidi'; } else { method_type = 'client_stream'; } } else { if (attrs.responseStream) { method_type = 'server_stream'; } else { method_type = 'unary'; } } var serialize = attrs.requestSerialize; var deserialize = attrs.responseDeserialize; Client.prototype[name] = requester_makers[method_type]( attrs.path, serialize, deserialize); Client.prototype[name].serialize = serialize; Client.prototype[name].deserialize = deserialize; }); return Client; }; /** * Return the underlying channel object for the specified client * @param {Client} client * @return {Channel} The channel */ exports.getClientChannel = function(client) { return client.$channel; }; /** * Wait for the client to be ready. The callback will be called when the * client has successfully connected to the server, and it will be called * with an error if the attempt to connect to the server has unrecoverablly * failed or if the deadline expires. This function will make the channel * start connecting if it has not already done so. * @param {Client} client The client to wait on * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass * Infinity to wait forever. * @param {function(Error)} callback The callback to call when done attempting * to connect. */ exports.waitForClientReady = function(client, deadline, callback) { var checkState = function(err) { if (err) { callback(new Error('Failed to connect before the deadline')); } var new_state = client.$channel.getConnectivityState(true); if (new_state === grpc.connectivityState.READY) { callback(); } else if (new_state === grpc.connectivityState.FATAL_FAILURE) { callback(new Error('Failed to connect to server')); } else { client.$channel.watchConnectivityState(new_state, deadline, checkState); } }; checkState(); }; /** * Creates a constructor for clients for the given service * @param {ProtoBuf.Reflect.Service} service The service to generate a client * for * @return {function(string, Object)} New client constructor */ exports.makeProtobufClientConstructor = function(service) { var method_attrs = common.getProtobufServiceAttrs(service, service.name); var Client = exports.makeClientConstructor( method_attrs, common.fullyQualifiedName(service)); Client.service = service; return Client; }; /** * Map of status code names to status codes */ exports.status = grpc.status; /** * See docs for client.callError */ exports.callError = grpc.callError; grpc-0.11.1/src/node/src/server.js0000644000175000017500000005614312600663151017077 0ustar apollockapollock/* * * 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. * */ /** * Server module * @module */ 'use strict'; var _ = require('lodash'); var grpc = require('bindings')('grpc.node'); var common = require('./common'); var Metadata = require('./metadata'); var stream = require('stream'); var Readable = stream.Readable; var Writable = stream.Writable; var Duplex = stream.Duplex; var util = require('util'); var EventEmitter = require('events').EventEmitter; /** * Handle an error on a call by sending it as a status * @access private * @param {grpc.Call} call The call to send the error on * @param {Object} error The error object */ function handleError(call, error) { var statusMetadata = new Metadata(); var status = { code: grpc.status.UNKNOWN, details: 'Unknown Error' }; if (error.hasOwnProperty('message')) { status.details = error.message; } if (error.hasOwnProperty('code')) { status.code = error.code; if (error.hasOwnProperty('details')) { status.details = error.details; } } if (error.hasOwnProperty('metadata')) { statusMetadata = error.metadata; } status.metadata = statusMetadata._getCoreRepresentation(); var error_batch = {}; if (!call.metadataSent) { error_batch[grpc.opType.SEND_INITIAL_METADATA] = (new Metadata())._getCoreRepresentation(); } error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; call.startBatch(error_batch, function(){}); } /** * Wait for the client to close, then emit a cancelled event if the client * cancelled. * @access private * @param {grpc.Call} call The call object to wait on * @param {EventEmitter} emitter The event emitter to emit the cancelled event * on */ function waitForCancel(call, emitter) { var cancel_batch = {}; cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; call.startBatch(cancel_batch, function(err, result) { if (err) { emitter.emit('error', err); } if (result.cancelled) { emitter.cancelled = true; emitter.emit('cancelled'); } }); } /** * Send a response to a unary or client streaming call. * @access private * @param {grpc.Call} call The call to respond on * @param {*} value The value to respond with * @param {function(*):Buffer=} serialize Serialization function for the * response * @param {Metadata=} metadata Optional trailing metadata to send with status * @param {number=} flags Flags for modifying how the message is sent. * Defaults to 0. */ function sendUnaryResponse(call, value, serialize, metadata, flags) { var end_batch = {}; var statusMetadata = new Metadata(); var status = { code: grpc.status.OK, details: 'OK' }; if (metadata) { statusMetadata = metadata; } status.metadata = statusMetadata._getCoreRepresentation(); if (!call.metadataSent) { end_batch[grpc.opType.SEND_INITIAL_METADATA] = (new Metadata())._getCoreRepresentation(); call.metadataSent = true; } var message = serialize(value); message.grpcWriteFlags = flags; end_batch[grpc.opType.SEND_MESSAGE] = message; end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; call.startBatch(end_batch, function (){}); } /** * Initialize a writable stream. This is used for both the writable and duplex * stream constructors. * @access private * @param {Writable} stream The stream to set up * @param {function(*):Buffer=} Serialization function for responses */ function setUpWritable(stream, serialize) { stream.finished = false; stream.status = { code : grpc.status.OK, details : 'OK', metadata : new Metadata() }; stream.serialize = common.wrapIgnoreNull(serialize); function sendStatus() { var batch = {}; if (!stream.call.metadataSent) { stream.call.metadataSent = true; batch[grpc.opType.SEND_INITIAL_METADATA] = (new Metadata())._getCoreRepresentation(); } if (stream.status.metadata) { stream.status.metadata = stream.status.metadata._getCoreRepresentation(); } batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status; stream.call.startBatch(batch, function(){}); } stream.on('finish', sendStatus); /** * Set the pending status to a given error status. If the error does not have * code or details properties, the code will be set to grpc.status.UNKNOWN * and the details will be set to 'Unknown Error'. * @param {Error} err The error object */ function setStatus(err) { var code = grpc.status.UNKNOWN; var details = 'Unknown Error'; var metadata = new Metadata(); if (err.hasOwnProperty('message')) { details = err.message; } if (err.hasOwnProperty('code')) { code = err.code; if (err.hasOwnProperty('details')) { details = err.details; } } if (err.hasOwnProperty('metadata')) { metadata = err.metadata; } stream.status = {code: code, details: details, metadata: metadata}; } /** * Terminate the call. This includes indicating that reads are done, draining * all pending writes, and sending the given error as a status * @param {Error} err The error object * @this GrpcServerStream */ function terminateCall(err) { // Drain readable data setStatus(err); stream.end(); } stream.on('error', terminateCall); /** * Override of Writable#end method that allows for sending metadata with a * success status. * @param {Metadata=} metadata Metadata to send with the status */ stream.end = function(metadata) { if (metadata) { stream.status.metadata = metadata; } Writable.prototype.end.call(this); }; } /** * Initialize a readable stream. This is used for both the readable and duplex * stream constructors. * @access private * @param {Readable} stream The stream to initialize * @param {function(Buffer):*=} deserialize Deserialization function for * incoming data. */ function setUpReadable(stream, deserialize) { stream.deserialize = common.wrapIgnoreNull(deserialize); stream.finished = false; stream.reading = false; stream.terminate = function() { stream.finished = true; stream.on('data', function() {}); }; stream.on('cancelled', function() { stream.terminate(); }); } util.inherits(ServerWritableStream, Writable); /** * A stream that the server can write to. Used for calls that are streaming from * the server side. * @constructor * @param {grpc.Call} call The call object to send data with * @param {function(*):Buffer=} serialize Serialization function for writes */ function ServerWritableStream(call, serialize) { Writable.call(this, {objectMode: true}); this.call = call; this.finished = false; setUpWritable(this, serialize); } /** * Start writing a chunk of data. This is an implementation of a method required * for implementing stream.Writable. * @access private * @param {Buffer} chunk The chunk of data to write * @param {string} encoding Used to pass write flags * @param {function(Error=)} callback Callback to indicate that the write is * complete */ function _write(chunk, encoding, callback) { /* jshint validthis: true */ var batch = {}; var self = this; if (!this.call.metadataSent) { batch[grpc.opType.SEND_INITIAL_METADATA] = (new Metadata())._getCoreRepresentation(); this.call.metadataSent = true; } var message = this.serialize(chunk); if (_.isFinite(encoding)) { /* Attach the encoding if it is a finite number. This is the closest we * can get to checking that it is valid flags */ message.grpcWriteFlags = encoding; } batch[grpc.opType.SEND_MESSAGE] = message; this.call.startBatch(batch, function(err, value) { if (err) { self.emit('error', err); return; } callback(); }); } ServerWritableStream.prototype._write = _write; /** * Send the initial metadata for a writable stream. * @param {Metadata} responseMetadata Metadata to send */ function sendMetadata(responseMetadata) { /* jshint validthis: true */ var self = this; if (!this.call.metadataSent) { this.call.metadataSent = true; var batch = []; batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata._getCoreRepresentation(); this.call.startBatch(batch, function(err) { if (err) { self.emit('error', err); return; } }); } } /** * @inheritdoc * @alias module:src/server~ServerWritableStream#sendMetadata */ ServerWritableStream.prototype.sendMetadata = sendMetadata; util.inherits(ServerReadableStream, Readable); /** * A stream that the server can read from. Used for calls that are streaming * from the client side. * @constructor * @param {grpc.Call} call The call object to read data with * @param {function(Buffer):*=} deserialize Deserialization function for reads */ function ServerReadableStream(call, deserialize) { Readable.call(this, {objectMode: true}); this.call = call; setUpReadable(this, deserialize); } /** * Start reading from the gRPC data source. This is an implementation of a * method required for implementing stream.Readable * @access private * @param {number} size Ignored */ function _read(size) { /* jshint validthis: true */ var self = this; /** * Callback to be called when a READ event is received. Pushes the data onto * the read queue and starts reading again if applicable * @param {grpc.Event} event READ event object */ function readCallback(err, event) { if (err) { self.terminate(); return; } if (self.finished) { self.push(null); return; } var data = event.read; var deserialized; try { deserialized = self.deserialize(data); } catch (e) { e.code = grpc.status.INVALID_ARGUMENT; self.emit('error', e); return; } if (self.push(deserialized) && data !== null) { var read_batch = {}; read_batch[grpc.opType.RECV_MESSAGE] = true; self.call.startBatch(read_batch, readCallback); } else { self.reading = false; } } if (self.finished) { self.push(null); } else { if (!self.reading) { self.reading = true; var batch = {}; batch[grpc.opType.RECV_MESSAGE] = true; self.call.startBatch(batch, readCallback); } } } ServerReadableStream.prototype._read = _read; util.inherits(ServerDuplexStream, Duplex); /** * A stream that the server can read from or write to. Used for calls with * duplex streaming. * @constructor * @param {grpc.Call} call Call object to proxy * @param {function(*):Buffer=} serialize Serialization function for requests * @param {function(Buffer):*=} deserialize Deserialization function for * responses */ function ServerDuplexStream(call, serialize, deserialize) { Duplex.call(this, {objectMode: true}); this.call = call; setUpWritable(this, serialize); setUpReadable(this, deserialize); } ServerDuplexStream.prototype._read = _read; ServerDuplexStream.prototype._write = _write; ServerDuplexStream.prototype.sendMetadata = sendMetadata; /** * Get the endpoint this call/stream is connected to. * @return {string} The URI of the endpoint */ function getPeer() { /* jshint validthis: true */ return this.call.getPeer(); } ServerReadableStream.prototype.getPeer = getPeer; ServerWritableStream.prototype.getPeer = getPeer; ServerDuplexStream.prototype.getPeer = getPeer; /** * Fully handle a unary call * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Metadata} metadata Metadata from the client */ function handleUnary(call, handler, metadata) { var emitter = new EventEmitter(); emitter.sendMetadata = function(responseMetadata) { if (!call.metadataSent) { call.metadataSent = true; var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata._getCoreRepresentation(); call.startBatch(batch, function() {}); } }; emitter.getPeer = function() { return call.getPeer(); }; emitter.on('error', function(error) { handleError(call, error); }); emitter.metadata = metadata; waitForCancel(call, emitter); emitter.call = call; var batch = {}; batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(batch, function(err, result) { if (err) { handleError(call, err); return; } try { emitter.request = handler.deserialize(result.read); } catch (e) { e.code = grpc.status.INVALID_ARGUMENT; handleError(call, e); return; } if (emitter.cancelled) { return; } handler.func(emitter, function sendUnaryData(err, value, trailer, flags) { if (err) { if (trailer) { err.metadata = trailer; } handleError(call, err); } else { sendUnaryResponse(call, value, handler.serialize, trailer, flags); } }); }); } /** * Fully handle a server streaming call * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Metadata} metadata Metadata from the client */ function handleServerStreaming(call, handler, metadata) { var stream = new ServerWritableStream(call, handler.serialize); waitForCancel(call, stream); stream.metadata = metadata; var batch = {}; batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(batch, function(err, result) { if (err) { stream.emit('error', err); return; } try { stream.request = handler.deserialize(result.read); } catch (e) { e.code = grpc.status.INVALID_ARGUMENT; stream.emit('error', e); return; } handler.func(stream); }); } /** * Fully handle a client streaming call * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Metadata} metadata Metadata from the client */ function handleClientStreaming(call, handler, metadata) { var stream = new ServerReadableStream(call, handler.deserialize); stream.sendMetadata = function(responseMetadata) { if (!call.metadataSent) { call.metadataSent = true; var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata._getCoreRepresentation(); call.startBatch(batch, function() {}); } }; stream.on('error', function(error) { handleError(call, error); }); waitForCancel(call, stream); stream.metadata = metadata; handler.func(stream, function(err, value, trailer, flags) { stream.terminate(); if (err) { if (trailer) { err.metadata = trailer; } handleError(call, err); } else { sendUnaryResponse(call, value, handler.serialize, trailer, flags); } }); } /** * Fully handle a bidirectional streaming call * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Metadata} metadata Metadata from the client */ function handleBidiStreaming(call, handler, metadata) { var stream = new ServerDuplexStream(call, handler.serialize, handler.deserialize); waitForCancel(call, stream); stream.metadata = metadata; handler.func(stream); } var streamHandlers = { unary: handleUnary, server_stream: handleServerStreaming, client_stream: handleClientStreaming, bidi: handleBidiStreaming }; /** * Constructs a server object that stores request handlers and delegates * incoming requests to those handlers * @constructor * @param {Object=} options Options that should be passed to the internal server * implementation */ function Server(options) { this.handlers = {}; var handlers = this.handlers; var server = new grpc.Server(options); this._server = server; this.started = false; /** * Start the server and begin handling requests * @this Server */ this.start = function() { if (this.started) { throw new Error('Server is already running'); } this.started = true; console.log('Server starting'); _.each(handlers, function(handler, handler_name) { console.log('Serving', handler_name); }); server.start(); /** * Handles the SERVER_RPC_NEW event. If there is a handler associated with * the requested method, use that handler to respond to the request. Then * wait for the next request * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW */ function handleNewCall(err, event) { if (err) { return; } var details = event.new_call; var call = details.call; var method = details.method; var metadata = Metadata._fromCoreRepresentation(details.metadata); if (method === null) { return; } server.requestCall(handleNewCall); var handler; if (handlers.hasOwnProperty(method)) { handler = handlers[method]; } else { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = (new Metadata())._getCoreRepresentation(); batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { code: grpc.status.UNIMPLEMENTED, details: 'This method is not available on this server.', metadata: {} }; batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; call.startBatch(batch, function() {}); return; } streamHandlers[handler.type](call, handler, metadata); } server.requestCall(handleNewCall); }; /** * Gracefully shuts down the server. The server will stop receiving new calls, * and any pending calls will complete. The callback will be called when all * pending calls have completed and the server is fully shut down. This method * is idempotent with itself and forceShutdown. * @param {function()} callback The shutdown complete callback */ this.tryShutdown = function(callback) { server.tryShutdown(callback); }; /** * Forcibly shuts down the server. The server will stop receiving new calls * and cancel all pending calls. When it returns, the server has shut down. * This method is idempotent with itself and tryShutdown, and it will trigger * any outstanding tryShutdown callbacks. */ this.forceShutdown = function() { server.forceShutdown(); }; } /** * Registers a handler to handle the named method. Fails if there already is * a handler for the given method. Returns true on success * @param {string} name The name of the method that the provided function should * handle/respond to. * @param {function} handler Function that takes a stream of request values and * returns a stream of response values * @param {function(*):Buffer} serialize Serialization function for responses * @param {function(Buffer):*} deserialize Deserialization function for requests * @param {string} type The streaming type of method that this handles * @return {boolean} True if the handler was set. False if a handler was already * set for that name. */ Server.prototype.register = function(name, handler, serialize, deserialize, type) { if (this.handlers.hasOwnProperty(name)) { return false; } this.handlers[name] = { func: handler, serialize: serialize, deserialize: deserialize, type: type }; return true; }; /** * Add a service to the server, with a corresponding implementation. If you are * generating this from a proto file, you should instead use * addProtoService. * @param {Object} service The service descriptor, as * {@link module:src/common.getProtobufServiceAttrs} returns * @param {Object} implementation Map of method names to * method implementation for the provided service. */ Server.prototype.addService = function(service, implementation) { if (this.started) { throw new Error('Can\'t add a service to a started server.'); } var self = this; _.each(service, function(attrs, name) { var method_type; if (attrs.requestStream) { if (attrs.responseStream) { method_type = 'bidi'; } else { method_type = 'client_stream'; } } else { if (attrs.responseStream) { method_type = 'server_stream'; } else { method_type = 'unary'; } } if (implementation[name] === undefined) { throw new Error('Method handler for ' + attrs.path + ' not provided.'); } var serialize = attrs.responseSerialize; var deserialize = attrs.requestDeserialize; var register_success = self.register(attrs.path, _.bind(implementation[name], implementation), serialize, deserialize, method_type); if (!register_success) { throw new Error('Method handler for ' + attrs.path + ' already provided.'); } }); }; /** * Add a proto service to the server, with a corresponding implementation * @param {Protobuf.Reflect.Service} service The proto service descriptor * @param {Object} implementation Map of method names to * method implementation for the provided service. */ Server.prototype.addProtoService = function(service, implementation) { this.addService(common.getProtobufServiceAttrs(service), implementation); }; /** * Binds the server to the given port, with SSL enabled if creds is given * @param {string} port The port that the server should bind on, in the format * "address:port" * @param {boolean=} creds Server credential object to be used for SSL. Pass * nothing for an insecure port */ Server.prototype.bind = function(port, creds) { if (this.started) { throw new Error('Can\'t bind an already running server to an address'); } return this._server.addHttp2Port(port, creds); }; /** * @see module:src/server~Server */ exports.Server = Server; grpc-0.11.1/src/node/ext/0000755000175000017500000000000012600663151015233 5ustar apollockapollockgrpc-0.11.1/src/node/ext/call.cc0000644000175000017500000005667612600663151016501 0ustar apollockapollock/* * * 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 #include #include #include #include "grpc/support/log.h" #include "grpc/grpc.h" #include "grpc/support/alloc.h" #include "grpc/support/time.h" #include "byte_buffer.h" #include "call.h" #include "channel.h" #include "completion_queue_async_worker.h" #include "timeval.h" using std::unique_ptr; using std::shared_ptr; using std::vector; namespace grpc { namespace node { using Nan::Callback; using Nan::EscapableHandleScope; using Nan::HandleScope; using Nan::Maybe; using Nan::MaybeLocal; using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; using v8::Array; using v8::Boolean; using v8::Exception; using v8::External; using v8::Function; using v8::FunctionTemplate; using v8::Integer; using v8::Local; using v8::Number; using v8::Object; using v8::ObjectTemplate; using v8::Uint32; using v8::String; using v8::Value; Callback *Call::constructor; Persistent Call::fun_tpl; bool EndsWith(const char *str, const char *substr) { return strcmp(str+strlen(str)-strlen(substr), substr) == 0; } bool CreateMetadataArray(Local metadata, grpc_metadata_array *array, shared_ptr resources) { HandleScope scope; grpc_metadata_array_init(array); Local keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked(); for (unsigned int i = 0; i < keys->Length(); i++) { Local current_key = Nan::To( Nan::Get(keys, i).ToLocalChecked()).ToLocalChecked(); Local value_array = Nan::Get(metadata, current_key).ToLocalChecked(); if (!value_array->IsArray()) { return false; } array->capacity += Local::Cast(value_array)->Length(); } array->metadata = reinterpret_cast( gpr_malloc(array->capacity * sizeof(grpc_metadata))); for (unsigned int i = 0; i < keys->Length(); i++) { Local current_key(keys->Get(i)->ToString()); Utf8String *utf8_key = new Utf8String(current_key); resources->strings.push_back(unique_ptr(utf8_key)); Local values = Local::Cast( Nan::Get(metadata, current_key).ToLocalChecked()); for (unsigned int j = 0; j < values->Length(); j++) { Local value = Nan::Get(values, j).ToLocalChecked(); grpc_metadata *current = &array->metadata[array->count]; current->key = **utf8_key; // Only allow binary headers for "-bin" keys if (EndsWith(current->key, "-bin")) { if (::node::Buffer::HasInstance(value)) { current->value = ::node::Buffer::Data(value); current->value_length = ::node::Buffer::Length(value); PersistentValue *handle = new PersistentValue(value); resources->handles.push_back(unique_ptr(handle)); } else { return false; } } else { if (value->IsString()) { Local string_value = Nan::To(value).ToLocalChecked(); Utf8String *utf8_value = new Utf8String(string_value); resources->strings.push_back(unique_ptr(utf8_value)); current->value = **utf8_value; current->value_length = string_value->Length(); } else { return false; } } array->count += 1; } } return true; } Local ParseMetadata(const grpc_metadata_array *metadata_array) { EscapableHandleScope scope; grpc_metadata *metadata_elements = metadata_array->metadata; size_t length = metadata_array->count; std::map size_map; std::map index_map; for (unsigned int i = 0; i < length; i++) { const char *key = metadata_elements[i].key; if (size_map.count(key)) { size_map[key] += 1; } else { size_map[key] = 1; } index_map[key] = 0; } Local metadata_object = Nan::New(); for (unsigned int i = 0; i < length; i++) { grpc_metadata* elem = &metadata_elements[i]; Local key_string = Nan::New(elem->key).ToLocalChecked(); Local array; MaybeLocal maybe_array = Nan::Get(metadata_object, key_string); if (maybe_array.IsEmpty() || !maybe_array.ToLocalChecked()->IsArray()) { array = Nan::New(size_map[elem->key]); Nan::Set(metadata_object, key_string, array); } else { array = Local::Cast(maybe_array.ToLocalChecked()); } if (EndsWith(elem->key, "-bin")) { Nan::Set(array, index_map[elem->key], Nan::CopyBuffer(elem->value, elem->value_length).ToLocalChecked()); } else { Nan::Set(array, index_map[elem->key], Nan::New(elem->value).ToLocalChecked()); } index_map[elem->key] += 1; } return scope.Escape(metadata_object); } Local Op::GetOpType() const { EscapableHandleScope scope; return scope.Escape(Nan::New(GetTypeString()).ToLocalChecked()); } Op::~Op() { } class SendMetadataOp : public Op { public: Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(Nan::True()); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { if (!value->IsObject()) { return false; } grpc_metadata_array array; MaybeLocal maybe_metadata = Nan::To(value); if (maybe_metadata.IsEmpty()) { return false; } if (!CreateMetadataArray(maybe_metadata.ToLocalChecked(), &array, resources)) { return false; } out->data.send_initial_metadata.count = array.count; out->data.send_initial_metadata.metadata = array.metadata; return true; } protected: std::string GetTypeString() const { return "send_metadata"; } }; class SendMessageOp : public Op { public: Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(Nan::True()); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { if (!::node::Buffer::HasInstance(value)) { return false; } Local object_value = Nan::To(value).ToLocalChecked(); MaybeLocal maybe_flag_value = Nan::Get( object_value, Nan::New("grpcWriteFlags").ToLocalChecked()); if (!maybe_flag_value.IsEmpty()) { Local flag_value = maybe_flag_value.ToLocalChecked(); if (flag_value->IsUint32()) { Maybe maybe_flag = Nan::To(flag_value); out->flags = maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK; } } out->data.send_message = BufferToByteBuffer(value); PersistentValue *handle = new PersistentValue(value); resources->handles.push_back(unique_ptr(handle)); return true; } protected: std::string GetTypeString() const { return "send_message"; } }; class SendClientCloseOp : public Op { public: Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(Nan::True()); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { return true; } protected: std::string GetTypeString() const { return "client_close"; } }; class SendServerStatusOp : public Op { public: Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(Nan::True()); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { if (!value->IsObject()) { return false; } Local server_status = Nan::To(value).ToLocalChecked(); MaybeLocal maybe_metadata = Nan::Get( server_status, Nan::New("metadata").ToLocalChecked()); if (maybe_metadata.IsEmpty()) { return false; } if (!maybe_metadata.ToLocalChecked()->IsObject()) { return false; } Local metadata = Nan::To( maybe_metadata.ToLocalChecked()).ToLocalChecked(); MaybeLocal maybe_code = Nan::Get(server_status, Nan::New("code").ToLocalChecked()); if (maybe_code.IsEmpty()) { return false; } if (!maybe_code.ToLocalChecked()->IsUint32()) { return false; } uint32_t code = Nan::To(maybe_code.ToLocalChecked()).FromJust(); MaybeLocal maybe_details = Nan::Get( server_status, Nan::New("details").ToLocalChecked()); if (maybe_details.IsEmpty()) { return false; } if (!maybe_details.ToLocalChecked()->IsString()) { return false; } Local details = Nan::To( maybe_details.ToLocalChecked()).ToLocalChecked(); grpc_metadata_array array; if (!CreateMetadataArray(metadata, &array, resources)) { return false; } out->data.send_status_from_server.trailing_metadata_count = array.count; out->data.send_status_from_server.trailing_metadata = array.metadata; out->data.send_status_from_server.status = static_cast(code); Utf8String *str = new Utf8String(details); resources->strings.push_back(unique_ptr(str)); out->data.send_status_from_server.status_details = **str; return true; } protected: std::string GetTypeString() const { return "send_status"; } }; class GetMetadataOp : public Op { public: GetMetadataOp() { grpc_metadata_array_init(&recv_metadata); } ~GetMetadataOp() { grpc_metadata_array_destroy(&recv_metadata); } Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(ParseMetadata(&recv_metadata)); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { out->data.recv_initial_metadata = &recv_metadata; return true; } protected: std::string GetTypeString() const { return "metadata"; } private: grpc_metadata_array recv_metadata; }; class ReadMessageOp : public Op { public: ReadMessageOp() { recv_message = NULL; } ~ReadMessageOp() { if (recv_message != NULL) { grpc_byte_buffer_destroy(recv_message); } } Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(ByteBufferToBuffer(recv_message)); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { out->data.recv_message = &recv_message; return true; } protected: std::string GetTypeString() const { return "read"; } private: grpc_byte_buffer *recv_message; }; class ClientStatusOp : public Op { public: ClientStatusOp() { grpc_metadata_array_init(&metadata_array); status_details = NULL; details_capacity = 0; } ~ClientStatusOp() { grpc_metadata_array_destroy(&metadata_array); gpr_free(status_details); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { out->data.recv_status_on_client.trailing_metadata = &metadata_array; out->data.recv_status_on_client.status = &status; out->data.recv_status_on_client.status_details = &status_details; out->data.recv_status_on_client.status_details_capacity = &details_capacity; return true; } Local GetNodeValue() const { EscapableHandleScope scope; Local status_obj = Nan::New(); Nan::Set(status_obj, Nan::New("code").ToLocalChecked(), Nan::New(status)); if (status_details != NULL) { Nan::Set(status_obj, Nan::New("details").ToLocalChecked(), Nan::New(status_details).ToLocalChecked()); } Nan::Set(status_obj, Nan::New("metadata").ToLocalChecked(), ParseMetadata(&metadata_array)); return scope.Escape(status_obj); } protected: std::string GetTypeString() const { return "status"; } private: grpc_metadata_array metadata_array; grpc_status_code status; char *status_details; size_t details_capacity; }; class ServerCloseResponseOp : public Op { public: Local GetNodeValue() const { EscapableHandleScope scope; return scope.Escape(Nan::New(cancelled)); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { out->data.recv_close_on_server.cancelled = &cancelled; return true; } protected: std::string GetTypeString() const { return "cancelled"; } private: int cancelled; }; tag::tag(Callback *callback, OpVec *ops, shared_ptr resources) : callback(callback), ops(ops), resources(resources){ } tag::~tag() { delete callback; delete ops; } Local GetTagNodeValue(void *tag) { EscapableHandleScope scope; struct tag *tag_struct = reinterpret_cast(tag); Local tag_obj = Nan::New(); for (vector >::iterator it = tag_struct->ops->begin(); it != tag_struct->ops->end(); ++it) { Op *op_ptr = it->get(); Nan::Set(tag_obj, op_ptr->GetOpType(), op_ptr->GetNodeValue()); } return scope.Escape(tag_obj); } Callback *GetTagCallback(void *tag) { struct tag *tag_struct = reinterpret_cast(tag); return tag_struct->callback; } void DestroyTag(void *tag) { struct tag *tag_struct = reinterpret_cast(tag); delete tag_struct; } Call::Call(grpc_call *call) : wrapped_call(call) { } Call::~Call() { grpc_call_destroy(wrapped_call); } void Call::Init(Local exports) { HandleScope scope; Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("Call").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "startBatch", StartBatch); Nan::SetPrototypeMethod(tpl, "cancel", Cancel); Nan::SetPrototypeMethod(tpl, "cancelWithStatus", CancelWithStatus); Nan::SetPrototypeMethod(tpl, "getPeer", GetPeer); fun_tpl.Reset(tpl); Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set(exports, Nan::New("Call").ToLocalChecked(), ctr); constructor = new Callback(ctr); } bool Call::HasInstance(Local val) { HandleScope scope; return Nan::New(fun_tpl)->HasInstance(val); } Local Call::WrapStruct(grpc_call *call) { EscapableHandleScope scope; if (call == NULL) { return scope.Escape(Nan::Null()); } const int argc = 1; Local argv[argc] = {Nan::New( reinterpret_cast(call))}; MaybeLocal maybe_instance = Nan::NewInstance( constructor->GetFunction(), argc, argv); if (maybe_instance.IsEmpty()) { return scope.Escape(Nan::Null()); } else { return scope.Escape(maybe_instance.ToLocalChecked()); } } NAN_METHOD(Call::New) { if (info.IsConstructCall()) { Call *call; if (info[0]->IsExternal()) { Local ext = info[0].As(); // This option is used for wrapping an existing call grpc_call *call_value = reinterpret_cast(ext->Value()); call = new Call(call_value); } else { if (!Channel::HasInstance(info[0])) { return Nan::ThrowTypeError("Call's first argument must be a Channel"); } if (!info[1]->IsString()) { return Nan::ThrowTypeError("Call's second argument must be a string"); } if (!(info[2]->IsNumber() || info[2]->IsDate())) { return Nan::ThrowTypeError( "Call's third argument must be a date or a number"); } // These arguments are at the end because they are optional grpc_call *parent_call = NULL; if (Call::HasInstance(info[4])) { Call *parent_obj = ObjectWrap::Unwrap( Nan::To(info[4]).ToLocalChecked()); parent_call = parent_obj->wrapped_call; } else if (!(info[4]->IsUndefined() || info[4]->IsNull())) { return Nan::ThrowTypeError( "Call's fifth argument must be another call, if provided"); } gpr_uint32 propagate_flags = GRPC_PROPAGATE_DEFAULTS; if (info[5]->IsUint32()) { propagate_flags = Nan::To(info[5]).FromJust(); } else if (!(info[5]->IsUndefined() || info[5]->IsNull())) { return Nan::ThrowTypeError( "Call's sixth argument must be propagate flags, if provided"); } Local channel_object = Nan::To(info[0]).ToLocalChecked(); Channel *channel = ObjectWrap::Unwrap(channel_object); if (channel->GetWrappedChannel() == NULL) { return Nan::ThrowError("Call cannot be created from a closed channel"); } Utf8String method(info[1]); double deadline = Nan::To(info[2]).FromJust(); grpc_channel *wrapped_channel = channel->GetWrappedChannel(); grpc_call *wrapped_call; if (info[3]->IsString()) { Utf8String host_override(info[3]); wrapped_call = grpc_channel_create_call( wrapped_channel, parent_call, propagate_flags, CompletionQueueAsyncWorker::GetQueue(), *method, *host_override, MillisecondsToTimespec(deadline), NULL); } else if (info[3]->IsUndefined() || info[3]->IsNull()) { wrapped_call = grpc_channel_create_call( wrapped_channel, parent_call, propagate_flags, CompletionQueueAsyncWorker::GetQueue(), *method, NULL, MillisecondsToTimespec(deadline), NULL); } else { return Nan::ThrowTypeError("Call's fourth argument must be a string"); } call = new Call(wrapped_call); info.This()->SetHiddenValue(Nan::New("channel_").ToLocalChecked(), channel_object); } call->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } else { const int argc = 4; Local argv[argc] = {info[0], info[1], info[2], info[3]}; MaybeLocal maybe_instance = constructor->GetFunction()->NewInstance( argc, argv); if (maybe_instance.IsEmpty()) { // There's probably a pending exception return; } else { info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); } } } NAN_METHOD(Call::StartBatch) { if (!Call::HasInstance(info.This())) { return Nan::ThrowTypeError("startBatch can only be called on Call objects"); } if (!info[0]->IsObject()) { return Nan::ThrowError("startBatch's first argument must be an object"); } if (!info[1]->IsFunction()) { return Nan::ThrowError("startBatch's second argument must be a callback"); } Local callback_func = info[1].As(); Call *call = ObjectWrap::Unwrap(info.This()); shared_ptr resources(new Resources); Local obj = Nan::To(info[0]).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked(); size_t nops = keys->Length(); vector ops(nops); unique_ptr op_vector(new OpVec()); for (unsigned int i = 0; i < nops; i++) { unique_ptr op; MaybeLocal maybe_key = Nan::Get(keys, i); if (maybe_key.IsEmpty() || (!maybe_key.ToLocalChecked()->IsUint32())) { return Nan::ThrowError( "startBatch's first argument's keys must be integers"); } uint32_t type = Nan::To(maybe_key.ToLocalChecked()).FromJust(); ops[i].op = static_cast(type); ops[i].flags = 0; ops[i].reserved = NULL; switch (type) { case GRPC_OP_SEND_INITIAL_METADATA: op.reset(new SendMetadataOp()); break; case GRPC_OP_SEND_MESSAGE: op.reset(new SendMessageOp()); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: op.reset(new SendClientCloseOp()); break; case GRPC_OP_SEND_STATUS_FROM_SERVER: op.reset(new SendServerStatusOp()); break; case GRPC_OP_RECV_INITIAL_METADATA: op.reset(new GetMetadataOp()); break; case GRPC_OP_RECV_MESSAGE: op.reset(new ReadMessageOp()); break; case GRPC_OP_RECV_STATUS_ON_CLIENT: op.reset(new ClientStatusOp()); break; case GRPC_OP_RECV_CLOSE_ON_SERVER: op.reset(new ServerCloseResponseOp()); break; default: return Nan::ThrowError("Argument object had an unrecognized key"); } if (!op->ParseOp(obj->Get(type), &ops[i], resources)) { return Nan::ThrowTypeError("Incorrectly typed arguments to startBatch"); } op_vector->push_back(std::move(op)); } Callback *callback = new Callback(callback_func); grpc_call_error error = grpc_call_start_batch( call->wrapped_call, &ops[0], nops, new struct tag( callback, op_vector.release(), resources), NULL); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("startBatch failed", error)); } CompletionQueueAsyncWorker::Next(); } NAN_METHOD(Call::Cancel) { if (!Call::HasInstance(info.This())) { return Nan::ThrowTypeError("cancel can only be called on Call objects"); } Call *call = ObjectWrap::Unwrap(info.This()); grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("cancel failed", error)); } } NAN_METHOD(Call::CancelWithStatus) { Nan::HandleScope scope; if (!HasInstance(info.This())) { return Nan::ThrowTypeError("cancel can only be called on Call objects"); } if (!info[0]->IsUint32()) { return Nan::ThrowTypeError( "cancelWithStatus's first argument must be a status code"); } if (!info[1]->IsString()) { return Nan::ThrowTypeError( "cancelWithStatus's second argument must be a string"); } Call *call = ObjectWrap::Unwrap(info.This()); grpc_status_code code = static_cast( Nan::To(info[0]).FromJust()); Utf8String details(info[0]); grpc_call_cancel_with_status(call->wrapped_call, code, *details, NULL); } NAN_METHOD(Call::GetPeer) { Nan::HandleScope scope; if (!HasInstance(info.This())) { return Nan::ThrowTypeError("getPeer can only be called on Call objects"); } Call *call = ObjectWrap::Unwrap(info.This()); char *peer = grpc_call_get_peer(call->wrapped_call); Local peer_value = Nan::New(peer).ToLocalChecked(); gpr_free(peer); info.GetReturnValue().Set(peer_value); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/completion_queue_async_worker.cc0000644000175000017500000000724212600663151023712 0ustar apollockapollock/* * * 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 #include #include "grpc/grpc.h" #include "grpc/support/log.h" #include "grpc/support/time.h" #include "completion_queue_async_worker.h" #include "call.h" namespace grpc { namespace node { const int max_queue_threads = 2; using v8::Function; using v8::Local; using v8::Object; using v8::Value; grpc_completion_queue *CompletionQueueAsyncWorker::queue; int CompletionQueueAsyncWorker::current_threads; int CompletionQueueAsyncWorker::waiting_next_calls; CompletionQueueAsyncWorker::CompletionQueueAsyncWorker() : Nan::AsyncWorker(NULL) {} CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {} void CompletionQueueAsyncWorker::Execute() { result = grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); if (!result.success) { SetErrorMessage("The async function encountered an error"); } } grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; } void CompletionQueueAsyncWorker::Next() { Nan::HandleScope scope; if (current_threads < max_queue_threads) { CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker(); Nan::AsyncQueueWorker(worker); } else { waiting_next_calls += 1; } } void CompletionQueueAsyncWorker::Init(Local exports) { Nan::HandleScope scope; current_threads = 0; waiting_next_calls = 0; queue = grpc_completion_queue_create(NULL); } void CompletionQueueAsyncWorker::HandleOKCallback() { Nan::HandleScope scope; if (waiting_next_calls > 0) { waiting_next_calls -= 1; CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker(); Nan::AsyncQueueWorker(worker); } else { current_threads -= 1; } Nan::Callback *callback = GetTagCallback(result.tag); Local argv[] = {Nan::Null(), GetTagNodeValue(result.tag)}; callback->Call(2, argv); DestroyTag(result.tag); } void CompletionQueueAsyncWorker::HandleErrorCallback() { Nan::HandleScope scope; Nan::Callback *callback = GetTagCallback(result.tag); Local argv[] = {Nan::Error(ErrorMessage())}; callback->Call(1, argv); DestroyTag(result.tag); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/timeval.cc0000644000175000017500000000515512600663151017211 0ustar apollockapollock/* * * 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 #include "grpc/grpc.h" #include "grpc/support/time.h" #include "timeval.h" namespace grpc { namespace node { gpr_timespec MillisecondsToTimespec(double millis) { if (millis == std::numeric_limits::infinity()) { return gpr_inf_future(GPR_CLOCK_REALTIME); } else if (millis == -std::numeric_limits::infinity()) { return gpr_inf_past(GPR_CLOCK_REALTIME); } else { return gpr_time_from_micros(static_cast(millis * 1000), GPR_CLOCK_REALTIME); } } double TimespecToMilliseconds(gpr_timespec timespec) { timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME); if (gpr_time_cmp(timespec, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) { return std::numeric_limits::infinity(); } else if (gpr_time_cmp(timespec, gpr_inf_past(GPR_CLOCK_REALTIME)) == 0) { return -std::numeric_limits::infinity(); } else { return (static_cast(timespec.tv_sec) * 1000 + static_cast(timespec.tv_nsec) / 1000000); } } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/credentials.cc0000644000175000017500000002057012600663151020043 0ustar apollockapollock/* * * 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 #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "grpc/support/log.h" #include "credentials.h" namespace grpc { namespace node { using Nan::Callback; using Nan::EscapableHandleScope; using Nan::HandleScope; using Nan::Maybe; using Nan::MaybeLocal; using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; using v8::Exception; using v8::External; using v8::Function; using v8::FunctionTemplate; using v8::Integer; using v8::Local; using v8::Object; using v8::ObjectTemplate; using v8::Value; Nan::Callback *Credentials::constructor; Persistent Credentials::fun_tpl; Credentials::Credentials(grpc_credentials *credentials) : wrapped_credentials(credentials) {} Credentials::~Credentials() { grpc_credentials_release(wrapped_credentials); } void Credentials::Init(Local exports) { HandleScope scope; Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("Credentials").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); fun_tpl.Reset(tpl); Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set(ctr, Nan::New("createDefault").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateDefault)).ToLocalChecked()); Nan::Set(ctr, Nan::New("createSsl").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateSsl)).ToLocalChecked()); Nan::Set(ctr, Nan::New("createComposite").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateComposite)).ToLocalChecked()); Nan::Set(ctr, Nan::New("createGce").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateGce)).ToLocalChecked()); Nan::Set(ctr, Nan::New("createIam").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateIam)).ToLocalChecked()); Nan::Set(ctr, Nan::New("createInsecure").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateInsecure)).ToLocalChecked()); Nan::Set(exports, Nan::New("Credentials").ToLocalChecked(), ctr); constructor = new Nan::Callback(ctr); } bool Credentials::HasInstance(Local val) { HandleScope scope; return Nan::New(fun_tpl)->HasInstance(val); } Local Credentials::WrapStruct(grpc_credentials *credentials) { EscapableHandleScope scope; const int argc = 1; Local argv[argc] = { Nan::New(reinterpret_cast(credentials))}; MaybeLocal maybe_instance = Nan::NewInstance( constructor->GetFunction(), argc, argv); if (maybe_instance.IsEmpty()) { return scope.Escape(Nan::Null()); } else { return scope.Escape(maybe_instance.ToLocalChecked()); } } grpc_credentials *Credentials::GetWrappedCredentials() { return wrapped_credentials; } NAN_METHOD(Credentials::New) { if (info.IsConstructCall()) { if (!info[0]->IsExternal()) { return Nan::ThrowTypeError( "Credentials can only be created with the provided functions"); } Local ext = info[0].As(); grpc_credentials *creds_value = reinterpret_cast(ext->Value()); Credentials *credentials = new Credentials(creds_value); credentials->Wrap(info.This()); info.GetReturnValue().Set(info.This()); return; } else { const int argc = 1; Local argv[argc] = {info[0]}; MaybeLocal maybe_instance = constructor->GetFunction()->NewInstance( argc, argv); if (maybe_instance.IsEmpty()) { // There's probably a pending exception return; } else { info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); } } } NAN_METHOD(Credentials::CreateDefault) { grpc_credentials *creds = grpc_google_default_credentials_create(); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { info.GetReturnValue().Set(WrapStruct(creds)); } } NAN_METHOD(Credentials::CreateSsl) { char *root_certs = NULL; grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL}; if (::node::Buffer::HasInstance(info[0])) { root_certs = ::node::Buffer::Data(info[0]); } else if (!(info[0]->IsNull() || info[0]->IsUndefined())) { return Nan::ThrowTypeError("createSsl's first argument must be a Buffer"); } if (::node::Buffer::HasInstance(info[1])) { key_cert_pair.private_key = ::node::Buffer::Data(info[1]); } else if (!(info[1]->IsNull() || info[1]->IsUndefined())) { return Nan::ThrowTypeError( "createSSl's second argument must be a Buffer if provided"); } if (::node::Buffer::HasInstance(info[2])) { key_cert_pair.cert_chain = ::node::Buffer::Data(info[2]); } else if (!(info[2]->IsNull() || info[2]->IsUndefined())) { return Nan::ThrowTypeError( "createSSl's third argument must be a Buffer if provided"); } grpc_credentials *creds = grpc_ssl_credentials_create( root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { info.GetReturnValue().Set(WrapStruct(creds)); } } NAN_METHOD(Credentials::CreateComposite) { if (!HasInstance(info[0])) { return Nan::ThrowTypeError( "createComposite's first argument must be a Credentials object"); } if (!HasInstance(info[1])) { return Nan::ThrowTypeError( "createComposite's second argument must be a Credentials object"); } Credentials *creds1 = ObjectWrap::Unwrap( Nan::To(info[0]).ToLocalChecked()); Credentials *creds2 = ObjectWrap::Unwrap( Nan::To(info[1]).ToLocalChecked()); grpc_credentials *creds = grpc_composite_credentials_create( creds1->wrapped_credentials, creds2->wrapped_credentials, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { info.GetReturnValue().Set(WrapStruct(creds)); } } NAN_METHOD(Credentials::CreateGce) { Nan::HandleScope scope; grpc_credentials *creds = grpc_google_compute_engine_credentials_create(NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { info.GetReturnValue().Set(WrapStruct(creds)); } } NAN_METHOD(Credentials::CreateIam) { if (!info[0]->IsString()) { return Nan::ThrowTypeError("createIam's first argument must be a string"); } if (!info[1]->IsString()) { return Nan::ThrowTypeError("createIam's second argument must be a string"); } Utf8String auth_token(info[0]); Utf8String auth_selector(info[1]); grpc_credentials *creds = grpc_google_iam_credentials_create(*auth_token, *auth_selector, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { info.GetReturnValue().Set(WrapStruct(creds)); } } NAN_METHOD(Credentials::CreateInsecure) { info.GetReturnValue().Set(WrapStruct(NULL)); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/timeval.h0000644000175000017500000000353612600663151017054 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_TIMEVAL_H_ #define NET_GRPC_NODE_TIMEVAL_H_ #include "grpc/support/time.h" namespace grpc { namespace node { double TimespecToMilliseconds(gpr_timespec time); gpr_timespec MillisecondsToTimespec(double millis); } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_TIMEVAL_H_ grpc-0.11.1/src/node/ext/server.cc0000644000175000017500000002603212600663151017053 0ustar apollockapollock/* * * 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 #include "server.h" #include #include #include #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "grpc/support/log.h" #include "call.h" #include "completion_queue_async_worker.h" #include "server_credentials.h" #include "timeval.h" namespace grpc { namespace node { using Nan::Callback; using Nan::EscapableHandleScope; using Nan::HandleScope; using Nan::Maybe; using Nan::MaybeLocal; using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; using std::unique_ptr; using v8::Array; using v8::Boolean; using v8::Date; using v8::Exception; using v8::Function; using v8::FunctionTemplate; using v8::Local; using v8::Number; using v8::Object; using v8::String; using v8::Value; Nan::Callback *Server::constructor; Persistent Server::fun_tpl; class NewCallOp : public Op { public: NewCallOp() { call = NULL; grpc_call_details_init(&details); grpc_metadata_array_init(&request_metadata); } ~NewCallOp() { grpc_call_details_destroy(&details); grpc_metadata_array_destroy(&request_metadata); } Local GetNodeValue() const { Nan::EscapableHandleScope scope; if (call == NULL) { return scope.Escape(Nan::Null()); } Local obj = Nan::New(); Nan::Set(obj, Nan::New("call").ToLocalChecked(), Call::WrapStruct(call)); Nan::Set(obj, Nan::New("method").ToLocalChecked(), Nan::New(details.method).ToLocalChecked()); Nan::Set(obj, Nan::New("host").ToLocalChecked(), Nan::New(details.host).ToLocalChecked()); Nan::Set(obj, Nan::New("deadline").ToLocalChecked(), Nan::New( TimespecToMilliseconds(details.deadline)).ToLocalChecked()); Nan::Set(obj, Nan::New("metadata").ToLocalChecked(), ParseMetadata(&request_metadata)); return scope.Escape(obj); } bool ParseOp(Local value, grpc_op *out, shared_ptr resources) { return true; } grpc_call *call; grpc_call_details details; grpc_metadata_array request_metadata; protected: std::string GetTypeString() const { return "new_call"; } }; Server::Server(grpc_server *server) : wrapped_server(server) { shutdown_queue = grpc_completion_queue_create(NULL); grpc_server_register_completion_queue(server, shutdown_queue, NULL); } Server::~Server() { this->ShutdownServer(); grpc_completion_queue_shutdown(this->shutdown_queue); grpc_server_destroy(this->wrapped_server); grpc_completion_queue_destroy(this->shutdown_queue); } void Server::Init(Local exports) { HandleScope scope; Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("Server").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "requestCall", RequestCall); Nan::SetPrototypeMethod(tpl, "addHttp2Port", AddHttp2Port); Nan::SetPrototypeMethod(tpl, "start", Start); Nan::SetPrototypeMethod(tpl, "tryShutdown", TryShutdown); Nan::SetPrototypeMethod(tpl, "forceShutdown", ForceShutdown); fun_tpl.Reset(tpl); Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set(exports, Nan::New("Server").ToLocalChecked(), ctr); constructor = new Callback(ctr); } bool Server::HasInstance(Local val) { HandleScope scope; return Nan::New(fun_tpl)->HasInstance(val); } void Server::ShutdownServer() { grpc_server_shutdown_and_notify(this->wrapped_server, this->shutdown_queue, NULL); grpc_server_cancel_all_calls(this->wrapped_server); grpc_completion_queue_pluck(this->shutdown_queue, NULL, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } NAN_METHOD(Server::New) { /* If this is not a constructor call, make a constructor call and return the result */ if (!info.IsConstructCall()) { const int argc = 1; Local argv[argc] = {info[0]}; MaybeLocal maybe_instance = constructor->GetFunction()->NewInstance( argc, argv); if (maybe_instance.IsEmpty()) { // There's probably a pending exception return; } else { info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); return; } } grpc_server *wrapped_server; grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue(); if (info[0]->IsUndefined()) { wrapped_server = grpc_server_create(NULL, NULL); } else if (info[0]->IsObject()) { Local args_hash = Nan::To(info[0]).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked(); grpc_channel_args channel_args; channel_args.num_args = keys->Length(); channel_args.args = reinterpret_cast( calloc(channel_args.num_args, sizeof(grpc_arg))); /* These are used to keep all strings until then end of the block, then destroy them */ std::vector key_strings(keys->Length()); std::vector value_strings(keys->Length()); for (unsigned int i = 0; i < channel_args.num_args; i++) { MaybeLocal maybe_key = Nan::To( Nan::Get(keys, i).ToLocalChecked()); if (maybe_key.IsEmpty()) { free(channel_args.args); return Nan::ThrowTypeError("Arg keys must be strings"); } Local current_key = maybe_key.ToLocalChecked(); Local current_value = Nan::Get(args_hash, current_key).ToLocalChecked(); key_strings[i] = new Utf8String(current_key); channel_args.args[i].key = **key_strings[i]; if (current_value->IsInt32()) { channel_args.args[i].type = GRPC_ARG_INTEGER; channel_args.args[i].value.integer = Nan::To( current_value).FromJust(); } else if (current_value->IsString()) { channel_args.args[i].type = GRPC_ARG_STRING; value_strings[i] = new Utf8String(current_value); channel_args.args[i].value.string = **value_strings[i]; } else { free(channel_args.args); return Nan::ThrowTypeError("Arg values must be strings"); } } wrapped_server = grpc_server_create(&channel_args, NULL); free(channel_args.args); } else { return Nan::ThrowTypeError("Server expects an object"); } grpc_server_register_completion_queue(wrapped_server, queue, NULL); Server *server = new Server(wrapped_server); server->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } NAN_METHOD(Server::RequestCall) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError("requestCall can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(info.This()); NewCallOp *op = new NewCallOp(); unique_ptr ops(new OpVec()); ops->push_back(unique_ptr(op)); grpc_call_error error = grpc_server_request_call( server->wrapped_server, &op->call, &op->details, &op->request_metadata, CompletionQueueAsyncWorker::GetQueue(), CompletionQueueAsyncWorker::GetQueue(), new struct tag(new Callback(info[0].As()), ops.release(), shared_ptr(nullptr))); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("requestCall failed", error)); } CompletionQueueAsyncWorker::Next(); } NAN_METHOD(Server::AddHttp2Port) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError( "addHttp2Port can only be called on a Server"); } if (!info[0]->IsString()) { return Nan::ThrowTypeError( "addHttp2Port's first argument must be a String"); } if (!ServerCredentials::HasInstance(info[1])) { return Nan::ThrowTypeError( "addHttp2Port's second argument must be ServerCredentials"); } Server *server = ObjectWrap::Unwrap(info.This()); ServerCredentials *creds_object = ObjectWrap::Unwrap( Nan::To(info[1]).ToLocalChecked()); grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials(); int port; if (creds == NULL) { port = grpc_server_add_insecure_http2_port(server->wrapped_server, *Utf8String(info[0])); } else { port = grpc_server_add_secure_http2_port(server->wrapped_server, *Utf8String(info[0]), creds); } info.GetReturnValue().Set(Nan::New(port)); } NAN_METHOD(Server::Start) { Nan::HandleScope scope; if (!HasInstance(info.This())) { return Nan::ThrowTypeError("start can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(info.This()); grpc_server_start(server->wrapped_server); } NAN_METHOD(Server::TryShutdown) { Nan::HandleScope scope; if (!HasInstance(info.This())) { return Nan::ThrowTypeError("tryShutdown can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(info.This()); unique_ptr ops(new OpVec()); grpc_server_shutdown_and_notify( server->wrapped_server, CompletionQueueAsyncWorker::GetQueue(), new struct tag(new Nan::Callback(info[0].As()), ops.release(), shared_ptr(nullptr))); CompletionQueueAsyncWorker::Next(); } NAN_METHOD(Server::ForceShutdown) { Nan::HandleScope scope; if (!HasInstance(info.This())) { return Nan::ThrowTypeError("forceShutdown can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(info.This()); server->ShutdownServer(); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/channel.h0000644000175000017500000000523112600663151017015 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_CHANNEL_H_ #define NET_GRPC_NODE_CHANNEL_H_ #include #include #include "grpc/grpc.h" namespace grpc { namespace node { /* Wrapper class for grpc_channel structs */ class Channel : public Nan::ObjectWrap { public: static void Init(v8::Local exports); static bool HasInstance(v8::Local val); /* This is used to typecheck javascript objects before converting them to this type */ static v8::Persistent prototype; /* Returns the grpc_channel struct that this object wraps */ grpc_channel *GetWrappedChannel(); private: explicit Channel(grpc_channel *channel); ~Channel(); // Prevent copying Channel(const Channel &); Channel &operator=(const Channel &); static NAN_METHOD(New); static NAN_METHOD(Close); static NAN_METHOD(GetTarget); static NAN_METHOD(GetConnectivityState); static NAN_METHOD(WatchConnectivityState); static Nan::Callback *constructor; static Nan::Persistent fun_tpl; grpc_channel *wrapped_channel; }; } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_CHANNEL_H_ grpc-0.11.1/src/node/ext/server_credentials.cc0000644000175000017500000001716412600663151021436 0ustar apollockapollock/* * * 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 #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "grpc/support/log.h" #include "server_credentials.h" namespace grpc { namespace node { using Nan::Callback; using Nan::EscapableHandleScope; using Nan::HandleScope; using Nan::Maybe; using Nan::MaybeLocal; using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; using v8::Array; using v8::Exception; using v8::External; using v8::Function; using v8::FunctionTemplate; using v8::Integer; using v8::Local; using v8::Object; using v8::ObjectTemplate; using v8::String; using v8::Value; Nan::Callback *ServerCredentials::constructor; Persistent ServerCredentials::fun_tpl; ServerCredentials::ServerCredentials(grpc_server_credentials *credentials) : wrapped_credentials(credentials) {} ServerCredentials::~ServerCredentials() { grpc_server_credentials_release(wrapped_credentials); } void ServerCredentials::Init(Local exports) { Nan::HandleScope scope; Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("ServerCredentials").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Local ctr = tpl->GetFunction(); Nan::Set(ctr, Nan::New("createSsl").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateSsl)).ToLocalChecked()); Nan::Set(ctr, Nan::New("createInsecure").ToLocalChecked(), Nan::GetFunction( Nan::New(CreateInsecure)).ToLocalChecked()); fun_tpl.Reset(tpl); constructor = new Nan::Callback(ctr); Nan::Set(exports, Nan::New("ServerCredentials").ToLocalChecked(), ctr); } bool ServerCredentials::HasInstance(Local val) { Nan::HandleScope scope; return Nan::New(fun_tpl)->HasInstance(val); } Local ServerCredentials::WrapStruct( grpc_server_credentials *credentials) { Nan::EscapableHandleScope scope; const int argc = 1; Local argv[argc] = { Nan::New(reinterpret_cast(credentials))}; MaybeLocal maybe_instance = Nan::NewInstance( constructor->GetFunction(), argc, argv); if (maybe_instance.IsEmpty()) { return scope.Escape(Nan::Null()); } else { return scope.Escape(maybe_instance.ToLocalChecked()); } } grpc_server_credentials *ServerCredentials::GetWrappedServerCredentials() { return wrapped_credentials; } NAN_METHOD(ServerCredentials::New) { if (info.IsConstructCall()) { if (!info[0]->IsExternal()) { return Nan::ThrowTypeError( "ServerCredentials can only be created with the provide functions"); } Local ext = info[0].As(); grpc_server_credentials *creds_value = reinterpret_cast(ext->Value()); ServerCredentials *credentials = new ServerCredentials(creds_value); credentials->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } else { const int argc = 1; Local argv[argc] = {info[0]}; MaybeLocal maybe_instance = constructor->GetFunction()->NewInstance( argc, argv); if (maybe_instance.IsEmpty()) { // There's probably a pending exception return; } else { info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); } } } NAN_METHOD(ServerCredentials::CreateSsl) { Nan::HandleScope scope; char *root_certs = NULL; if (::node::Buffer::HasInstance(info[0])) { root_certs = ::node::Buffer::Data(info[0]); } else if (!(info[0]->IsNull() || info[0]->IsUndefined())) { return Nan::ThrowTypeError( "createSSl's first argument must be a Buffer if provided"); } if (!info[1]->IsArray()) { return Nan::ThrowTypeError( "createSsl's second argument must be a list of objects"); } int force_client_auth = 0; if (info[2]->IsBoolean()) { force_client_auth = (int)Nan::To(info[2]).FromJust(); } else if (!(info[2]->IsUndefined() || info[2]->IsNull())) { return Nan::ThrowTypeError( "createSsl's third argument must be a boolean if provided"); } Local pair_list = Local::Cast(info[1]); uint32_t key_cert_pair_count = pair_list->Length(); grpc_ssl_pem_key_cert_pair *key_cert_pairs = new grpc_ssl_pem_key_cert_pair[ key_cert_pair_count]; Local key_key = Nan::New("private_key").ToLocalChecked(); Local cert_key = Nan::New("cert_chain").ToLocalChecked(); for(uint32_t i = 0; i < key_cert_pair_count; i++) { Local pair_val = Nan::Get(pair_list, i).ToLocalChecked(); if (!pair_val->IsObject()) { delete key_cert_pairs; return Nan::ThrowTypeError("Key/cert pairs must be objects"); } Local pair_obj = Nan::To(pair_val).ToLocalChecked(); MaybeLocal maybe_key = Nan::Get(pair_obj, key_key); if (maybe_key.IsEmpty()) { delete key_cert_pairs; return Nan::ThrowTypeError( "Key/cert pairs must have a private_key and a cert_chain"); } MaybeLocal maybe_cert = Nan::Get(pair_obj, cert_key); if (maybe_cert.IsEmpty()) { delete key_cert_pairs; return Nan::ThrowTypeError( "Key/cert pairs must have a private_key and a cert_chain"); } if (!::node::Buffer::HasInstance(maybe_key.ToLocalChecked())) { delete key_cert_pairs; return Nan::ThrowTypeError("private_key must be a Buffer"); } if (!::node::Buffer::HasInstance(maybe_cert.ToLocalChecked())) { delete key_cert_pairs; return Nan::ThrowTypeError("cert_chain must be a Buffer"); } key_cert_pairs[i].private_key = ::node::Buffer::Data( maybe_key.ToLocalChecked()); key_cert_pairs[i].cert_chain = ::node::Buffer::Data( maybe_cert.ToLocalChecked()); } grpc_server_credentials *creds = grpc_ssl_server_credentials_create( root_certs, key_cert_pairs, key_cert_pair_count, force_client_auth, NULL); delete key_cert_pairs; if (creds == NULL) { info.GetReturnValue().SetNull(); } else { info.GetReturnValue().Set(WrapStruct(creds)); } } NAN_METHOD(ServerCredentials::CreateInsecure) { info.GetReturnValue().Set(WrapStruct(NULL)); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/byte_buffer.h0000644000175000017500000000440012600663151017676 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_BYTE_BUFFER_H_ #define NET_GRPC_NODE_BYTE_BUFFER_H_ #include #include #include #include "grpc/grpc.h" namespace grpc { namespace node { /* Convert a Node.js Buffer to grpc_byte_buffer. Requires that ::node::Buffer::HasInstance(buffer) */ grpc_byte_buffer *BufferToByteBuffer(v8::Local buffer); /* Convert a grpc_byte_buffer to a Node.js Buffer */ v8::Local ByteBufferToBuffer(grpc_byte_buffer *buffer); /* Convert a ::node::Buffer to a fast Buffer, as defined in the Node Buffer documentation */ v8::Local MakeFastBuffer(v8::Local slowBuffer); } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_BYTE_BUFFER_H_ grpc-0.11.1/src/node/ext/server.h0000644000175000017500000000552312600663151016717 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_SERVER_H_ #define NET_GRPC_NODE_SERVER_H_ #include #include #include "grpc/grpc.h" namespace grpc { namespace node { /* Wraps grpc_server as a JavaScript object. Provides a constructor and wrapper methods for grpc_server_create, grpc_server_request_call, grpc_server_add_http2_port, and grpc_server_start. */ class Server : public Nan::ObjectWrap { public: /* Initializes the Server class and exposes the constructor and wrapper methods to JavaScript */ static void Init(v8::Local exports); /* Tests whether the given value was constructed by this class's JavaScript constructor */ static bool HasInstance(v8::Local val); private: explicit Server(grpc_server *server); ~Server(); // Prevent copying Server(const Server &); Server &operator=(const Server &); void ShutdownServer(); static NAN_METHOD(New); static NAN_METHOD(RequestCall); static NAN_METHOD(AddHttp2Port); static NAN_METHOD(Start); static NAN_METHOD(TryShutdown); static NAN_METHOD(ForceShutdown); static Nan::Callback *constructor; static Nan::Persistent fun_tpl; grpc_server *wrapped_server; grpc_completion_queue *shutdown_queue; }; } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_SERVER_H_ grpc-0.11.1/src/node/ext/node_grpc.cc0000644000175000017500000002703612600663151017512 0ustar apollockapollock/* * * 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 #include #include #include "grpc/grpc.h" #include "call.h" #include "channel.h" #include "server.h" #include "completion_queue_async_worker.h" #include "credentials.h" #include "server_credentials.h" using v8::Local; using v8::Value; using v8::Object; using v8::Uint32; using v8::String; void InitStatusConstants(Local exports) { Nan::HandleScope scope; Local status = Nan::New(); Nan::Set(exports, Nan::New("status").ToLocalChecked(), status); Local OK(Nan::New(GRPC_STATUS_OK)); Nan::Set(status, Nan::New("OK").ToLocalChecked(), OK); Local CANCELLED(Nan::New(GRPC_STATUS_CANCELLED)); Nan::Set(status, Nan::New("CANCELLED").ToLocalChecked(), CANCELLED); Local UNKNOWN(Nan::New(GRPC_STATUS_UNKNOWN)); Nan::Set(status, Nan::New("UNKNOWN").ToLocalChecked(), UNKNOWN); Local INVALID_ARGUMENT( Nan::New(GRPC_STATUS_INVALID_ARGUMENT)); Nan::Set(status, Nan::New("INVALID_ARGUMENT").ToLocalChecked(), INVALID_ARGUMENT); Local DEADLINE_EXCEEDED( Nan::New(GRPC_STATUS_DEADLINE_EXCEEDED)); Nan::Set(status, Nan::New("DEADLINE_EXCEEDED").ToLocalChecked(), DEADLINE_EXCEEDED); Local NOT_FOUND(Nan::New(GRPC_STATUS_NOT_FOUND)); Nan::Set(status, Nan::New("NOT_FOUND").ToLocalChecked(), NOT_FOUND); Local ALREADY_EXISTS( Nan::New(GRPC_STATUS_ALREADY_EXISTS)); Nan::Set(status, Nan::New("ALREADY_EXISTS").ToLocalChecked(), ALREADY_EXISTS); Local PERMISSION_DENIED( Nan::New(GRPC_STATUS_PERMISSION_DENIED)); Nan::Set(status, Nan::New("PERMISSION_DENIED").ToLocalChecked(), PERMISSION_DENIED); Local UNAUTHENTICATED( Nan::New(GRPC_STATUS_UNAUTHENTICATED)); Nan::Set(status, Nan::New("UNAUTHENTICATED").ToLocalChecked(), UNAUTHENTICATED); Local RESOURCE_EXHAUSTED( Nan::New(GRPC_STATUS_RESOURCE_EXHAUSTED)); Nan::Set(status, Nan::New("RESOURCE_EXHAUSTED").ToLocalChecked(), RESOURCE_EXHAUSTED); Local FAILED_PRECONDITION( Nan::New(GRPC_STATUS_FAILED_PRECONDITION)); Nan::Set(status, Nan::New("FAILED_PRECONDITION").ToLocalChecked(), FAILED_PRECONDITION); Local ABORTED(Nan::New(GRPC_STATUS_ABORTED)); Nan::Set(status, Nan::New("ABORTED").ToLocalChecked(), ABORTED); Local OUT_OF_RANGE( Nan::New(GRPC_STATUS_OUT_OF_RANGE)); Nan::Set(status, Nan::New("OUT_OF_RANGE").ToLocalChecked(), OUT_OF_RANGE); Local UNIMPLEMENTED( Nan::New(GRPC_STATUS_UNIMPLEMENTED)); Nan::Set(status, Nan::New("UNIMPLEMENTED").ToLocalChecked(), UNIMPLEMENTED); Local INTERNAL(Nan::New(GRPC_STATUS_INTERNAL)); Nan::Set(status, Nan::New("INTERNAL").ToLocalChecked(), INTERNAL); Local UNAVAILABLE(Nan::New(GRPC_STATUS_UNAVAILABLE)); Nan::Set(status, Nan::New("UNAVAILABLE").ToLocalChecked(), UNAVAILABLE); Local DATA_LOSS(Nan::New(GRPC_STATUS_DATA_LOSS)); Nan::Set(status, Nan::New("DATA_LOSS").ToLocalChecked(), DATA_LOSS); } void InitCallErrorConstants(Local exports) { Nan::HandleScope scope; Local call_error = Nan::New(); Nan::Set(exports, Nan::New("callError").ToLocalChecked(), call_error); Local OK(Nan::New(GRPC_CALL_OK)); Nan::Set(call_error, Nan::New("OK").ToLocalChecked(), OK); Local ERROR(Nan::New(GRPC_CALL_ERROR)); Nan::Set(call_error, Nan::New("ERROR").ToLocalChecked(), ERROR); Local NOT_ON_SERVER( Nan::New(GRPC_CALL_ERROR_NOT_ON_SERVER)); Nan::Set(call_error, Nan::New("NOT_ON_SERVER").ToLocalChecked(), NOT_ON_SERVER); Local NOT_ON_CLIENT( Nan::New(GRPC_CALL_ERROR_NOT_ON_CLIENT)); Nan::Set(call_error, Nan::New("NOT_ON_CLIENT").ToLocalChecked(), NOT_ON_CLIENT); Local ALREADY_INVOKED( Nan::New(GRPC_CALL_ERROR_ALREADY_INVOKED)); Nan::Set(call_error, Nan::New("ALREADY_INVOKED").ToLocalChecked(), ALREADY_INVOKED); Local NOT_INVOKED( Nan::New(GRPC_CALL_ERROR_NOT_INVOKED)); Nan::Set(call_error, Nan::New("NOT_INVOKED").ToLocalChecked(), NOT_INVOKED); Local ALREADY_FINISHED( Nan::New(GRPC_CALL_ERROR_ALREADY_FINISHED)); Nan::Set(call_error, Nan::New("ALREADY_FINISHED").ToLocalChecked(), ALREADY_FINISHED); Local TOO_MANY_OPERATIONS( Nan::New(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS)); Nan::Set(call_error, Nan::New("TOO_MANY_OPERATIONS").ToLocalChecked(), TOO_MANY_OPERATIONS); Local INVALID_FLAGS( Nan::New(GRPC_CALL_ERROR_INVALID_FLAGS)); Nan::Set(call_error, Nan::New("INVALID_FLAGS").ToLocalChecked(), INVALID_FLAGS); } void InitOpTypeConstants(Local exports) { Nan::HandleScope scope; Local op_type = Nan::New(); Nan::Set(exports, Nan::New("opType").ToLocalChecked(), op_type); Local SEND_INITIAL_METADATA( Nan::New(GRPC_OP_SEND_INITIAL_METADATA)); Nan::Set(op_type, Nan::New("SEND_INITIAL_METADATA").ToLocalChecked(), SEND_INITIAL_METADATA); Local SEND_MESSAGE( Nan::New(GRPC_OP_SEND_MESSAGE)); Nan::Set(op_type, Nan::New("SEND_MESSAGE").ToLocalChecked(), SEND_MESSAGE); Local SEND_CLOSE_FROM_CLIENT( Nan::New(GRPC_OP_SEND_CLOSE_FROM_CLIENT)); Nan::Set(op_type, Nan::New("SEND_CLOSE_FROM_CLIENT").ToLocalChecked(), SEND_CLOSE_FROM_CLIENT); Local SEND_STATUS_FROM_SERVER( Nan::New(GRPC_OP_SEND_STATUS_FROM_SERVER)); Nan::Set(op_type, Nan::New("SEND_STATUS_FROM_SERVER").ToLocalChecked(), SEND_STATUS_FROM_SERVER); Local RECV_INITIAL_METADATA( Nan::New(GRPC_OP_RECV_INITIAL_METADATA)); Nan::Set(op_type, Nan::New("RECV_INITIAL_METADATA").ToLocalChecked(), RECV_INITIAL_METADATA); Local RECV_MESSAGE( Nan::New(GRPC_OP_RECV_MESSAGE)); Nan::Set(op_type, Nan::New("RECV_MESSAGE").ToLocalChecked(), RECV_MESSAGE); Local RECV_STATUS_ON_CLIENT( Nan::New(GRPC_OP_RECV_STATUS_ON_CLIENT)); Nan::Set(op_type, Nan::New("RECV_STATUS_ON_CLIENT").ToLocalChecked(), RECV_STATUS_ON_CLIENT); Local RECV_CLOSE_ON_SERVER( Nan::New(GRPC_OP_RECV_CLOSE_ON_SERVER)); Nan::Set(op_type, Nan::New("RECV_CLOSE_ON_SERVER").ToLocalChecked(), RECV_CLOSE_ON_SERVER); } void InitPropagateConstants(Local exports) { Nan::HandleScope scope; Local propagate = Nan::New(); Nan::Set(exports, Nan::New("propagate").ToLocalChecked(), propagate); Local DEADLINE(Nan::New(GRPC_PROPAGATE_DEADLINE)); Nan::Set(propagate, Nan::New("DEADLINE").ToLocalChecked(), DEADLINE); Local CENSUS_STATS_CONTEXT( Nan::New(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT)); Nan::Set(propagate, Nan::New("CENSUS_STATS_CONTEXT").ToLocalChecked(), CENSUS_STATS_CONTEXT); Local CENSUS_TRACING_CONTEXT( Nan::New(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT)); Nan::Set(propagate, Nan::New("CENSUS_TRACING_CONTEXT").ToLocalChecked(), CENSUS_TRACING_CONTEXT); Local CANCELLATION( Nan::New(GRPC_PROPAGATE_CANCELLATION)); Nan::Set(propagate, Nan::New("CANCELLATION").ToLocalChecked(), CANCELLATION); Local DEFAULTS(Nan::New(GRPC_PROPAGATE_DEFAULTS)); Nan::Set(propagate, Nan::New("DEFAULTS").ToLocalChecked(), DEFAULTS); } void InitConnectivityStateConstants(Local exports) { Nan::HandleScope scope; Local channel_state = Nan::New(); Nan::Set(exports, Nan::New("connectivityState").ToLocalChecked(), channel_state); Local IDLE(Nan::New(GRPC_CHANNEL_IDLE)); Nan::Set(channel_state, Nan::New("IDLE").ToLocalChecked(), IDLE); Local CONNECTING(Nan::New(GRPC_CHANNEL_CONNECTING)); Nan::Set(channel_state, Nan::New("CONNECTING").ToLocalChecked(), CONNECTING); Local READY(Nan::New(GRPC_CHANNEL_READY)); Nan::Set(channel_state, Nan::New("READY").ToLocalChecked(), READY); Local TRANSIENT_FAILURE( Nan::New(GRPC_CHANNEL_TRANSIENT_FAILURE)); Nan::Set(channel_state, Nan::New("TRANSIENT_FAILURE").ToLocalChecked(), TRANSIENT_FAILURE); Local FATAL_FAILURE( Nan::New(GRPC_CHANNEL_FATAL_FAILURE)); Nan::Set(channel_state, Nan::New("FATAL_FAILURE").ToLocalChecked(), FATAL_FAILURE); } void InitWriteFlags(Local exports) { Nan::HandleScope scope; Local write_flags = Nan::New(); Nan::Set(exports, Nan::New("writeFlags").ToLocalChecked(), write_flags); Local BUFFER_HINT(Nan::New(GRPC_WRITE_BUFFER_HINT)); Nan::Set(write_flags, Nan::New("BUFFER_HINT").ToLocalChecked(), BUFFER_HINT); Local NO_COMPRESS(Nan::New(GRPC_WRITE_NO_COMPRESS)); Nan::Set(write_flags, Nan::New("NO_COMPRESS").ToLocalChecked(), NO_COMPRESS); } void init(Local exports) { Nan::HandleScope scope; grpc_init(); InitStatusConstants(exports); InitCallErrorConstants(exports); InitOpTypeConstants(exports); InitPropagateConstants(exports); InitConnectivityStateConstants(exports); InitWriteFlags(exports); grpc::node::Call::Init(exports); grpc::node::Channel::Init(exports); grpc::node::Server::Init(exports); grpc::node::CompletionQueueAsyncWorker::Init(exports); grpc::node::Credentials::Init(exports); grpc::node::ServerCredentials::Init(exports); } NODE_MODULE(grpc, init) grpc-0.11.1/src/node/ext/byte_buffer.cc0000644000175000017500000000672612600663151020051 0ustar apollockapollock/* * * 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 #include #include #include "grpc/grpc.h" #include "grpc/byte_buffer_reader.h" #include "grpc/support/slice.h" #include "byte_buffer.h" namespace grpc { namespace node { using v8::Context; using v8::Function; using v8::Local; using v8::Object; using v8::Number; using v8::Value; grpc_byte_buffer *BufferToByteBuffer(Local buffer) { Nan::HandleScope scope; int length = ::node::Buffer::Length(buffer); char *data = ::node::Buffer::Data(buffer); gpr_slice slice = gpr_slice_malloc(length); memcpy(GPR_SLICE_START_PTR(slice), data, length); grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1)); gpr_slice_unref(slice); return byte_buffer; } Local ByteBufferToBuffer(grpc_byte_buffer *buffer) { Nan::EscapableHandleScope scope; if (buffer == NULL) { return scope.Escape(Nan::Null()); } size_t length = grpc_byte_buffer_length(buffer); char *result = reinterpret_cast(calloc(length, sizeof(char))); size_t offset = 0; grpc_byte_buffer_reader reader; grpc_byte_buffer_reader_init(&reader, buffer); gpr_slice next; while (grpc_byte_buffer_reader_next(&reader, &next) != 0) { memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); offset += GPR_SLICE_LENGTH(next); } return scope.Escape(MakeFastBuffer( Nan::NewBuffer(result, length).ToLocalChecked())); } Local MakeFastBuffer(Local slowBuffer) { Nan::EscapableHandleScope scope; Local globalObj = Nan::GetCurrentContext()->Global(); Local bufferConstructor = Local::Cast( globalObj->Get(Nan::New("Buffer").ToLocalChecked())); Local consArgs[3] = { slowBuffer, Nan::New(::node::Buffer::Length(slowBuffer)), Nan::New(0) }; Local fastBuffer = bufferConstructor->NewInstance(3, consArgs); return scope.Escape(fastBuffer); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/credentials.h0000644000175000017500000000562612600663151017712 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_CREDENTIALS_H_ #define NET_GRPC_NODE_CREDENTIALS_H_ #include #include #include "grpc/grpc.h" #include "grpc/grpc_security.h" namespace grpc { namespace node { /* Wrapper class for grpc_credentials structs */ class Credentials : public Nan::ObjectWrap { public: static void Init(v8::Local exports); static bool HasInstance(v8::Local val); /* Wrap a grpc_credentials struct in a javascript object */ static v8::Local WrapStruct(grpc_credentials *credentials); /* Returns the grpc_credentials struct that this object wraps */ grpc_credentials *GetWrappedCredentials(); private: explicit Credentials(grpc_credentials *credentials); ~Credentials(); // Prevent copying Credentials(const Credentials &); Credentials &operator=(const Credentials &); static NAN_METHOD(New); static NAN_METHOD(CreateDefault); static NAN_METHOD(CreateSsl); static NAN_METHOD(CreateComposite); static NAN_METHOD(CreateGce); static NAN_METHOD(CreateFake); static NAN_METHOD(CreateIam); static NAN_METHOD(CreateInsecure); static Nan::Callback *constructor; // Used for typechecking instances of this javascript class static Nan::Persistent fun_tpl; grpc_credentials *wrapped_credentials; }; } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_CREDENTIALS_H_ grpc-0.11.1/src/node/ext/channel.cc0000644000175000017500000002271112600663151017155 0ustar apollockapollock/* * * 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 #include "grpc/support/log.h" #include #include #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "call.h" #include "channel.h" #include "completion_queue_async_worker.h" #include "credentials.h" #include "timeval.h" namespace grpc { namespace node { using Nan::Callback; using Nan::EscapableHandleScope; using Nan::HandleScope; using Nan::Maybe; using Nan::MaybeLocal; using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; using v8::Array; using v8::Exception; using v8::Function; using v8::FunctionTemplate; using v8::Integer; using v8::Local; using v8::Number; using v8::Object; using v8::String; using v8::Value; Callback *Channel::constructor; Persistent Channel::fun_tpl; Channel::Channel(grpc_channel *channel) : wrapped_channel(channel) {} Channel::~Channel() { if (wrapped_channel != NULL) { grpc_channel_destroy(wrapped_channel); } } void Channel::Init(Local exports) { Nan::HandleScope scope; Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("Channel").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "close", Close); Nan::SetPrototypeMethod(tpl, "getTarget", GetTarget); Nan::SetPrototypeMethod(tpl, "getConnectivityState", GetConnectivityState); Nan::SetPrototypeMethod(tpl, "watchConnectivityState", WatchConnectivityState); fun_tpl.Reset(tpl); Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set(exports, Nan::New("Channel").ToLocalChecked(), ctr); constructor = new Callback(ctr); } bool Channel::HasInstance(Local val) { HandleScope scope; return Nan::New(fun_tpl)->HasInstance(val); } grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; } NAN_METHOD(Channel::New) { if (info.IsConstructCall()) { if (!info[0]->IsString()) { return Nan::ThrowTypeError( "Channel expects a string, a credential and an object"); } grpc_channel *wrapped_channel; // Owned by the Channel object Utf8String host(info[0]); grpc_credentials *creds; if (!Credentials::HasInstance(info[1])) { return Nan::ThrowTypeError( "Channel's second argument must be a credential"); } Credentials *creds_object = ObjectWrap::Unwrap( Nan::To(info[1]).ToLocalChecked()); creds = creds_object->GetWrappedCredentials(); grpc_channel_args *channel_args_ptr; if (info[2]->IsUndefined()) { channel_args_ptr = NULL; wrapped_channel = grpc_insecure_channel_create(*host, NULL, NULL); } else if (info[2]->IsObject()) { Local args_hash = Nan::To(info[2]).ToLocalChecked(); Local keys(Nan::GetOwnPropertyNames(args_hash).ToLocalChecked()); grpc_channel_args channel_args; channel_args.num_args = keys->Length(); channel_args.args = reinterpret_cast( calloc(channel_args.num_args, sizeof(grpc_arg))); /* These are used to keep all strings until then end of the block, then destroy them */ std::vector key_strings(keys->Length()); std::vector value_strings(keys->Length()); for (unsigned int i = 0; i < channel_args.num_args; i++) { MaybeLocal maybe_key = Nan::To( Nan::Get(keys, i).ToLocalChecked()); if (maybe_key.IsEmpty()) { free(channel_args.args); return Nan::ThrowTypeError("Arg keys must be strings"); } Local current_key = maybe_key.ToLocalChecked(); Local current_value = Nan::Get(args_hash, current_key).ToLocalChecked(); key_strings[i] = new Nan::Utf8String(current_key); channel_args.args[i].key = **key_strings[i]; if (current_value->IsInt32()) { channel_args.args[i].type = GRPC_ARG_INTEGER; channel_args.args[i].value.integer = Nan::To( current_value).FromJust(); } else if (current_value->IsString()) { channel_args.args[i].type = GRPC_ARG_STRING; value_strings[i] = new Nan::Utf8String(current_value); channel_args.args[i].value.string = **value_strings[i]; } else { free(channel_args.args); return Nan::ThrowTypeError("Arg values must be strings"); } } channel_args_ptr = &channel_args; } else { return Nan::ThrowTypeError("Channel expects a string and an object"); } if (creds == NULL) { wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr, NULL); } else { wrapped_channel = grpc_secure_channel_create(creds, *host, channel_args_ptr, NULL); } if (channel_args_ptr != NULL) { free(channel_args_ptr->args); } Channel *channel = new Channel(wrapped_channel); channel->Wrap(info.This()); info.GetReturnValue().Set(info.This()); return; } else { const int argc = 3; Local argv[argc] = {info[0], info[1], info[2]}; MaybeLocal maybe_instance = constructor->GetFunction()->NewInstance( argc, argv); if (maybe_instance.IsEmpty()) { // There's probably a pending exception return; } else { info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); } } } NAN_METHOD(Channel::Close) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError("close can only be called on Channel objects"); } Channel *channel = ObjectWrap::Unwrap(info.This()); if (channel->wrapped_channel != NULL) { grpc_channel_destroy(channel->wrapped_channel); channel->wrapped_channel = NULL; } } NAN_METHOD(Channel::GetTarget) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError("getTarget can only be called on Channel objects"); } Channel *channel = ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New( grpc_channel_get_target(channel->wrapped_channel)).ToLocalChecked()); } NAN_METHOD(Channel::GetConnectivityState) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError( "getConnectivityState can only be called on Channel objects"); } Channel *channel = ObjectWrap::Unwrap(info.This()); int try_to_connect = (int)info[0]->Equals(Nan::True()); info.GetReturnValue().Set( grpc_channel_check_connectivity_state(channel->wrapped_channel, try_to_connect)); } NAN_METHOD(Channel::WatchConnectivityState) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError( "watchConnectivityState can only be called on Channel objects"); } if (!info[0]->IsUint32()) { return Nan::ThrowTypeError( "watchConnectivityState's first argument must be a channel state"); } if (!(info[1]->IsNumber() || info[1]->IsDate())) { return Nan::ThrowTypeError( "watchConnectivityState's second argument must be a date or a number"); } if (!info[2]->IsFunction()) { return Nan::ThrowTypeError( "watchConnectivityState's third argument must be a callback"); } grpc_connectivity_state last_state = static_cast( Nan::To(info[0]).FromJust()); double deadline = Nan::To(info[1]).FromJust(); Local callback_func = info[2].As(); Nan::Callback *callback = new Callback(callback_func); Channel *channel = ObjectWrap::Unwrap(info.This()); unique_ptr ops(new OpVec()); grpc_channel_watch_connectivity_state( channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline), CompletionQueueAsyncWorker::GetQueue(), new struct tag(callback, ops.release(), shared_ptr(nullptr))); CompletionQueueAsyncWorker::Next(); } } // namespace node } // namespace grpc grpc-0.11.1/src/node/ext/call.h0000644000175000017500000001017712600663151016325 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_CALL_H_ #define NET_GRPC_NODE_CALL_H_ #include #include #include #include #include "grpc/grpc.h" #include "grpc/support/log.h" #include "channel.h" namespace grpc { namespace node { using std::unique_ptr; using std::shared_ptr; typedef Nan::Persistent> PersistentValue; /** * Helper function for throwing errors with a grpc_call_error value. * Modified from the answer by Gus Goose to * http://stackoverflow.com/questions/31794200. */ inline v8::Local nanErrorWithCode(const char *msg, grpc_call_error code) { Nan::EscapableHandleScope scope; v8::Local err = Nan::Error(msg).As(); Nan::Set(err, Nan::New("code").ToLocalChecked(), Nan::New(code)); return scope.Escape(err); } v8::Local ParseMetadata(const grpc_metadata_array *metadata_array); struct Resources { std::vector > strings; std::vector > handles; }; class Op { public: virtual v8::Local GetNodeValue() const = 0; virtual bool ParseOp(v8::Local value, grpc_op *out, shared_ptr resources) = 0; virtual ~Op(); v8::Local GetOpType() const; protected: virtual std::string GetTypeString() const = 0; }; typedef std::vector> OpVec; struct tag { tag(Nan::Callback *callback, OpVec *ops, shared_ptr resources); ~tag(); Nan::Callback *callback; OpVec *ops; shared_ptr resources; }; v8::Local GetTagNodeValue(void *tag); Nan::Callback *GetTagCallback(void *tag); void DestroyTag(void *tag); /* Wrapper class for grpc_call structs. */ class Call : public Nan::ObjectWrap { public: static void Init(v8::Local exports); static bool HasInstance(v8::Local val); /* Wrap a grpc_call struct in a javascript object */ static v8::Local WrapStruct(grpc_call *call); private: explicit Call(grpc_call *call); ~Call(); // Prevent copying Call(const Call &); Call &operator=(const Call &); static NAN_METHOD(New); static NAN_METHOD(StartBatch); static NAN_METHOD(Cancel); static NAN_METHOD(CancelWithStatus); static NAN_METHOD(GetPeer); static Nan::Callback *constructor; // Used for typechecking instances of this javascript class static Nan::Persistent fun_tpl; grpc_call *wrapped_call; }; } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_CALL_H_ grpc-0.11.1/src/node/ext/completion_queue_async_worker.h0000644000175000017500000000617512600663151023560 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ #define NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ #include #include "grpc/grpc.h" namespace grpc { namespace node { /* A worker that asynchronously calls completion_queue_next, and queues onto the node event loop a call to the function stored in the event's tag. */ class CompletionQueueAsyncWorker : public Nan::AsyncWorker { public: CompletionQueueAsyncWorker(); ~CompletionQueueAsyncWorker(); /* Calls completion_queue_next with the provided deadline, and stores the event if there was one or sets an error message if there was not */ void Execute(); /* Returns the completion queue attached to this class */ static grpc_completion_queue *GetQueue(); /* Convenience function to create a worker with the given arguments and queue it to run asynchronously */ static void Next(); /* Initialize the CompletionQueueAsyncWorker class */ static void Init(v8::Local exports); protected: /* Called when Execute has succeeded (completed without setting an error message). Calls the saved callback with the event that came from completion_queue_next */ void HandleOKCallback(); void HandleErrorCallback(); private: grpc_event result; static grpc_completion_queue *queue; // Number of grpc_completion_queue_next calls in the thread pool static int current_threads; // Number of grpc_completion_queue_next calls waiting to enter the thread pool static int waiting_next_calls; }; } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ grpc-0.11.1/src/node/ext/server_credentials.h0000644000175000017500000000554112600663151021274 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NET_GRPC_NODE_SERVER_CREDENTIALS_H_ #define NET_GRPC_NODE_SERVER_CREDENTIALS_H_ #include #include #include "grpc/grpc.h" #include "grpc/grpc_security.h" namespace grpc { namespace node { /* Wrapper class for grpc_server_credentials structs */ class ServerCredentials : public Nan::ObjectWrap { public: static void Init(v8::Local exports); static bool HasInstance(v8::Local val); /* Wrap a grpc_server_credentials struct in a javascript object */ static v8::Local WrapStruct(grpc_server_credentials *credentials); /* Returns the grpc_server_credentials struct that this object wraps */ grpc_server_credentials *GetWrappedServerCredentials(); private: explicit ServerCredentials(grpc_server_credentials *credentials); ~ServerCredentials(); // Prevent copying ServerCredentials(const ServerCredentials &); ServerCredentials &operator=(const ServerCredentials &); static NAN_METHOD(New); static NAN_METHOD(CreateSsl); static NAN_METHOD(CreateInsecure); static Nan::Callback *constructor; // Used for typechecking instances of this javascript class static Nan::Persistent fun_tpl; grpc_server_credentials *wrapped_credentials; }; } // namespace node } // namespace grpc #endif // NET_GRPC_NODE_SERVER_CREDENTIALS_H_ grpc-0.11.1/src/node/bin/0000755000175000017500000000000012600663151015203 5ustar apollockapollockgrpc-0.11.1/src/node/bin/README.md0000644000175000017500000000120212600663151016455 0ustar apollockapollock# Command Line Tools # Service Packager The command line tool `bin/service_packager`, when called with the following command line: ```bash service_packager proto_file -o output_path -n name -v version [-i input_path...] ``` Populates `output_path` with a node package consisting of a `package.json` populated with `name` and `version`, an `index.js`, a `LICENSE` file copied from gRPC, and a `service.json`, which is compiled from `proto_file` and the given `input_path`s. `require('output_path')` returns an object that is equivalent to ```js { client: require('grpc').load('service.json'), auth: require('google-auth-library') } ``` grpc-0.11.1/src/node/bin/service_packager0000755000175000017500000000014112600663151020422 0ustar apollockapollock#!/usr/bin/env node require(__dirname+'/../cli/service_packager.js').main(process.argv.slice(2));grpc-0.11.1/src/node/LICENSE0000644000175000017500000000270312600663151015442 0ustar apollockapollockCopyright 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. grpc-0.11.1/src/node/health_check/0000755000175000017500000000000012600663151017035 5ustar apollockapollockgrpc-0.11.1/src/node/health_check/health.proto0000644000175000017500000000353612600663151021376 0ustar apollockapollock// 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. syntax = "proto3"; package grpc.health.v1alpha; message HealthCheckRequest { string service = 1; } message HealthCheckResponse { enum ServingStatus { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; } ServingStatus status = 1; } service Health { rpc Check(HealthCheckRequest) returns (HealthCheckResponse); } grpc-0.11.1/src/node/health_check/health.js0000644000175000017500000000446612600663151020652 0ustar apollockapollock/* * * 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. * */ 'use strict'; var grpc = require('../'); var _ = require('lodash'); var health_proto = grpc.load(__dirname + '/health.proto'); var HealthClient = health_proto.grpc.health.v1alpha.Health; function HealthImplementation(statusMap) { this.statusMap = _.clone(statusMap); } HealthImplementation.prototype.setStatus = function(service, status) { this.statusMap[service] = status; }; HealthImplementation.prototype.check = function(call, callback){ var service = call.request.service; var status = _.get(this.statusMap, service, null); if (status === null) { callback({code:grpc.status.NOT_FOUND}); } else { callback(null, {status: status}); } }; module.exports = { Client: HealthClient, service: HealthClient.service, Implementation: HealthImplementation }; grpc-0.11.1/src/node/test/0000755000175000017500000000000012600663151015412 5ustar apollockapollockgrpc-0.11.1/src/node/test/test_messages.proto0000644000175000017500000000326112600663151021347 0ustar apollockapollock// 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. syntax = "proto3"; message LongValues { int64 int_64 = 1; uint64 uint_64 = 2; sint64 sint_64 = 3; fixed64 fixed_64 = 4; sfixed64 sfixed_64 = 5; }grpc-0.11.1/src/node/test/test_service.proto0000644000175000017500000000357612600663151021211 0ustar apollockapollock// 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. syntax = "proto3"; message Request { bool error = 1; } message Response { int32 count = 1; } service TestService { rpc Unary (Request) returns (Response) { } rpc ClientStream (stream Request) returns (Response) { } rpc ServerStream (Request) returns (stream Response) { } rpc BidiStream (stream Request) returns (stream Response) { } }grpc-0.11.1/src/node/test/interop_sanity_test.js0000644000175000017500000000716212600663151022064 0ustar apollockapollock/* * * 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. * */ 'use strict'; var interop_server = require('../interop/interop_server.js'); var interop_client = require('../interop/interop_client.js'); var server; var port; var name_override = 'foo.test.google.fr'; describe('Interop tests', function() { before(function(done) { var server_obj = interop_server.getServer(0, true); server = server_obj.server; server.start(); port = 'localhost:' + server_obj.port; done(); }); after(function() { server.forceShutdown(); }); // This depends on not using a binary stream it('should pass empty_unary', function(done) { interop_client.runTest(port, name_override, 'empty_unary', true, true, done); }); // This fails due to an unknown bug it('should pass large_unary', function(done) { interop_client.runTest(port, name_override, 'large_unary', true, true, done); }); it('should pass client_streaming', function(done) { interop_client.runTest(port, name_override, 'client_streaming', true, true, done); }); it('should pass server_streaming', function(done) { interop_client.runTest(port, name_override, 'server_streaming', true, true, done); }); it('should pass ping_pong', function(done) { interop_client.runTest(port, name_override, 'ping_pong', true, true, done); }); it('should pass empty_stream', function(done) { interop_client.runTest(port, name_override, 'empty_stream', true, true, done); }); it('should pass cancel_after_begin', function(done) { interop_client.runTest(port, name_override, 'cancel_after_begin', true, true, done); }); it('should pass cancel_after_first_response', function(done) { interop_client.runTest(port, name_override, 'cancel_after_first_response', true, true, done); }); it('should pass timeout_on_sleeping_server', function(done) { interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', true, true, done); }); }); grpc-0.11.1/src/node/test/health_test.js0000644000175000017500000000716212600663151020262 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var health = require('../health_check/health.js'); var grpc = require('../'); describe('Health Checking', function() { var statusMap = { '': 'SERVING', 'grpc.test.TestServiceNotServing': 'NOT_SERVING', 'grpc.test.TestServiceServing': 'SERVING' }; var healthServer = new grpc.Server(); healthServer.addProtoService(health.service, new health.Implementation(statusMap)); var healthClient; before(function() { var port_num = healthServer.bind('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); healthServer.start(); healthClient = new health.Client('localhost:' + port_num, grpc.Credentials.createInsecure()); }); after(function() { healthServer.forceShutdown(); }); it('should say an enabled service is SERVING', function(done) { healthClient.check({service: ''}, function(err, response) { assert.ifError(err); assert.strictEqual(response.status, 'SERVING'); done(); }); }); it('should say that a disabled service is NOT_SERVING', function(done) { healthClient.check({service: 'grpc.test.TestServiceNotServing'}, function(err, response) { assert.ifError(err); assert.strictEqual(response.status, 'NOT_SERVING'); done(); }); }); it('should say that an enabled service is SERVING', function(done) { healthClient.check({service: 'grpc.test.TestServiceServing'}, function(err, response) { assert.ifError(err); assert.strictEqual(response.status, 'SERVING'); done(); }); }); it('should get NOT_FOUND if the service is not registered', function(done) { healthClient.check({service: 'not_registered'}, function(err, response) { assert(err); assert.strictEqual(err.code, grpc.status.NOT_FOUND); done(); }); }); }); grpc-0.11.1/src/node/test/echo_service.proto0000644000175000017500000000326112600663151021137 0ustar apollockapollock// 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. syntax = "proto3"; message EchoMessage { string value = 1; int32 value2 = 2; } service EchoService { rpc Echo (EchoMessage) returns (EchoMessage); }grpc-0.11.1/src/node/test/test_service.json0000644000175000017500000000257712600663151021017 0ustar apollockapollock{ "package": null, "messages": [ { "name": "Request", "fields": [ { "rule": "optional", "type": "bool", "name": "error", "id": 1 } ] }, { "name": "Response", "fields": [ { "rule": "optional", "type": "int32", "name": "count", "id": 1 } ] } ], "services": [ { "name": "TestService", "options": {}, "rpc": { "Unary": { "request": "Request", "response": "Response", "options": {} }, "ClientStream": { "request": "Request", "response": "Response", "options": {} }, "ServerStream": { "request": "Request", "response": "Response", "options": {} }, "BidiStream": { "request": "Request", "response": "Response", "options": {} } } } ] }grpc-0.11.1/src/node/test/common_test.js0000644000175000017500000000751112600663151020303 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var common = require('../src/common.js'); var ProtoBuf = require('protobufjs'); var messages_proto = ProtoBuf.loadProtoFile( __dirname + '/test_messages.proto').build(); describe('Proto message serialize and deserialize', function() { var longSerialize = common.serializeCls(messages_proto.LongValues); var longDeserialize = common.deserializeCls(messages_proto.LongValues); var pos_value = '314159265358979'; var neg_value = '-27182818284590'; it('should preserve positive int64 values', function() { var serialized = longSerialize({int_64: pos_value}); assert.strictEqual(longDeserialize(serialized).int_64.toString(), pos_value); }); it('should preserve negative int64 values', function() { var serialized = longSerialize({int_64: neg_value}); assert.strictEqual(longDeserialize(serialized).int_64.toString(), neg_value); }); it('should preserve uint64 values', function() { var serialized = longSerialize({uint_64: pos_value}); assert.strictEqual(longDeserialize(serialized).uint_64.toString(), pos_value); }); it('should preserve positive sint64 values', function() { var serialized = longSerialize({sint_64: pos_value}); assert.strictEqual(longDeserialize(serialized).sint_64.toString(), pos_value); }); it('should preserve negative sint64 values', function() { var serialized = longSerialize({sint_64: neg_value}); assert.strictEqual(longDeserialize(serialized).sint_64.toString(), neg_value); }); it('should preserve fixed64 values', function() { var serialized = longSerialize({fixed_64: pos_value}); assert.strictEqual(longDeserialize(serialized).fixed_64.toString(), pos_value); }); it('should preserve positive sfixed64 values', function() { var serialized = longSerialize({sfixed_64: pos_value}); assert.strictEqual(longDeserialize(serialized).sfixed_64.toString(), pos_value); }); it('should preserve negative sfixed64 values', function() { var serialized = longSerialize({sfixed_64: neg_value}); assert.strictEqual(longDeserialize(serialized).sfixed_64.toString(), neg_value); }); }); grpc-0.11.1/src/node/test/metadata_test.js0000644000175000017500000001523512600663151020575 0ustar apollockapollock/* * * 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. * */ 'use strict'; var Metadata = require('../src/metadata.js'); var assert = require('assert'); describe('Metadata', function() { var metadata; beforeEach(function() { metadata = new Metadata(); }); describe('#set', function() { it('Only accepts string values for non "-bin" keys', function() { assert.throws(function() { metadata.set('key', new Buffer('value')); }); assert.doesNotThrow(function() { metadata.set('key', 'value'); }); }); it('Only accepts Buffer values for "-bin" keys', function() { assert.throws(function() { metadata.set('key-bin', 'value'); }); assert.doesNotThrow(function() { metadata.set('key-bin', new Buffer('value')); }); }); it('Rejects invalid keys', function() { assert.throws(function() { metadata.set('key$', 'value'); }); assert.throws(function() { metadata.set('', 'value'); }); }); it('Rejects values with non-ASCII characters', function() { assert.throws(function() { metadata.set('key', 'résumé'); }); }); it('Saves values that can be retrieved', function() { metadata.set('key', 'value'); assert.deepEqual(metadata.get('key'), ['value']); }); it('Overwrites previous values', function() { metadata.set('key', 'value1'); metadata.set('key', 'value2'); assert.deepEqual(metadata.get('key'), ['value2']); }); it('Normalizes keys', function() { metadata.set('Key', 'value1'); assert.deepEqual(metadata.get('key'), ['value1']); metadata.set('KEY', 'value2'); assert.deepEqual(metadata.get('key'), ['value2']); }); }); describe('#add', function() { it('Only accepts string values for non "-bin" keys', function() { assert.throws(function() { metadata.add('key', new Buffer('value')); }); assert.doesNotThrow(function() { metadata.add('key', 'value'); }); }); it('Only accepts Buffer values for "-bin" keys', function() { assert.throws(function() { metadata.add('key-bin', 'value'); }); assert.doesNotThrow(function() { metadata.add('key-bin', new Buffer('value')); }); }); it('Rejects invalid keys', function() { assert.throws(function() { metadata.add('key$', 'value'); }); assert.throws(function() { metadata.add('', 'value'); }); }); it('Saves values that can be retrieved', function() { metadata.add('key', 'value'); assert.deepEqual(metadata.get('key'), ['value']); }); it('Combines with previous values', function() { metadata.add('key', 'value1'); metadata.add('key', 'value2'); assert.deepEqual(metadata.get('key'), ['value1', 'value2']); }); it('Normalizes keys', function() { metadata.add('Key', 'value1'); assert.deepEqual(metadata.get('key'), ['value1']); metadata.add('KEY', 'value2'); assert.deepEqual(metadata.get('key'), ['value1', 'value2']); }); }); describe('#remove', function() { it('clears values from a key', function() { metadata.add('key', 'value'); metadata.remove('key'); assert.deepEqual(metadata.get('key'), []); }); it('Normalizes keys', function() { metadata.add('key', 'value'); metadata.remove('KEY'); assert.deepEqual(metadata.get('key'), []); }); }); describe('#get', function() { beforeEach(function() { metadata.add('key', 'value1'); metadata.add('key', 'value2'); metadata.add('key-bin', new Buffer('value')); }); it('gets all values associated with a key', function() { assert.deepEqual(metadata.get('key'), ['value1', 'value2']); }); it('Normalizes keys', function() { assert.deepEqual(metadata.get('KEY'), ['value1', 'value2']); }); it('returns an empty list for non-existent keys', function() { assert.deepEqual(metadata.get('non-existent-key'), []); }); it('returns Buffers for "-bin" keys', function() { assert(metadata.get('key-bin')[0] instanceof Buffer); }); }); describe('#getMap', function() { it('gets a map of keys to values', function() { metadata.add('key1', 'value1'); metadata.add('Key2', 'value2'); metadata.add('KEY3', 'value3'); assert.deepEqual(metadata.getMap(), {key1: 'value1', key2: 'value2', key3: 'value3'}); }); }); describe('#clone', function() { it('retains values from the original', function() { metadata.add('key', 'value'); var copy = metadata.clone(); assert.deepEqual(copy.get('key'), ['value']); }); it('Does not see newly added values', function() { metadata.add('key', 'value1'); var copy = metadata.clone(); metadata.add('key', 'value2'); assert.deepEqual(copy.get('key'), ['value1']); }); it('Does not add new values to the original', function() { metadata.add('key', 'value1'); var copy = metadata.clone(); copy.add('key', 'value2'); assert.deepEqual(metadata.get('key'), ['value1']); }); }); }); grpc-0.11.1/src/node/test/surface_test.js0000644000175000017500000007426012600663151020450 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var surface_client = require('../src/client.js'); var ProtoBuf = require('protobufjs'); var grpc = require('..'); var math_proto = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto'); var mathService = math_proto.lookup('math.Math'); var _ = require('lodash'); /** * This is used for testing functions with multiple asynchronous calls that * can happen in different orders. This should be passed the number of async * function invocations that can occur last, and each of those should call this * function's return value * @param {function()} done The function that should be called when a test is * complete. * @param {number} count The number of calls to the resulting function if the * test passes. * @return {function()} The function that should be called at the end of each * sequence of asynchronous functions. */ function multiDone(done, count) { return function() { count -= 1; if (count <= 0) { done(); } }; } var server_insecure_creds = grpc.ServerCredentials.createInsecure(); describe('File loader', function() { it('Should load a proto file by default', function() { assert.doesNotThrow(function() { grpc.load(__dirname + '/test_service.proto'); }); }); it('Should load a proto file with the proto format', function() { assert.doesNotThrow(function() { grpc.load(__dirname + '/test_service.proto', 'proto'); }); }); it('Should load a json file with the json format', function() { assert.doesNotThrow(function() { grpc.load(__dirname + '/test_service.json', 'json'); }); }); it('Should fail to load a file with an unknown format', function() { assert.throws(function() { grpc.load(__dirname + '/test_service.proto', 'fake_format'); }); }); }); describe('Server.prototype.addProtoService', function() { var server; var dummyImpls = { 'div': function() {}, 'divMany': function() {}, 'fib': function() {}, 'sum': function() {} }; beforeEach(function() { server = new grpc.Server(); }); afterEach(function() { server.forceShutdown(); }); it('Should succeed with a single service', function() { assert.doesNotThrow(function() { server.addProtoService(mathService, dummyImpls); }); }); it('Should fail with conflicting method names', function() { server.addProtoService(mathService, dummyImpls); assert.throws(function() { server.addProtoService(mathService, dummyImpls); }); }); it('Should fail with missing handlers', function() { assert.throws(function() { server.addProtoService(mathService, { 'div': function() {}, 'divMany': function() {}, 'fib': function() {} }); }, /math.Math.Sum/); }); it('Should fail if the server has been started', function() { server.start(); assert.throws(function() { server.addProtoService(mathService, dummyImpls); }); }); }); describe('Client constructor building', function() { var illegal_service_attrs = { $method : { path: '/illegal/$method', requestStream: false, responseStream: false, requestSerialize: _.identity, requestDeserialize: _.identity, responseSerialize: _.identity, responseDeserialize: _.identity } }; it('Should reject method names starting with $', function() { assert.throws(function() { grpc.makeGenericClientConstructor(illegal_service_attrs); }, /\$/); }); }); describe('waitForClientReady', function() { var server; var port; var Client; var client; before(function() { server = new grpc.Server(); port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); server.start(); Client = surface_client.makeProtobufClientConstructor(mathService); }); beforeEach(function() { client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); }); after(function() { server.forceShutdown(); }); it('should complete when called alone', function(done) { grpc.waitForClientReady(client, Infinity, function(error) { assert.ifError(error); done(); }); }); it('should complete when a call is initiated', function(done) { grpc.waitForClientReady(client, Infinity, function(error) { assert.ifError(error); done(); }); var call = client.div({}, function(err, response) {}); call.cancel(); }); it('should complete if called more than once', function(done) { done = multiDone(done, 2); grpc.waitForClientReady(client, Infinity, function(error) { assert.ifError(error); done(); }); grpc.waitForClientReady(client, Infinity, function(error) { assert.ifError(error); done(); }); }); it('should complete if called when already ready', function(done) { grpc.waitForClientReady(client, Infinity, function(error) { assert.ifError(error); grpc.waitForClientReady(client, Infinity, function(error) { assert.ifError(error); done(); }); }); }); }); describe('Echo service', function() { var server; var client; before(function() { var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto'); var echo_service = test_proto.lookup('EchoService'); server = new grpc.Server(); server.addProtoService(echo_service, { echo: function(call, callback) { callback(null, call.request); } }); var port = server.bind('localhost:0', server_insecure_creds); var Client = surface_client.makeProtobufClientConstructor(echo_service); client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); server.start(); }); after(function() { server.forceShutdown(); }); it('should echo the recieved message directly', function(done) { client.echo({value: 'test value', value2: 3}, function(error, response) { assert.ifError(error); assert.deepEqual(response, {value: 'test value', value2: 3}); done(); }); }); }); describe('Generic client and server', function() { function toString(val) { return val.toString(); } function toBuffer(str) { return new Buffer(str); } var string_service_attrs = { 'capitalize' : { path: '/string/capitalize', requestStream: false, responseStream: false, requestSerialize: toBuffer, requestDeserialize: toString, responseSerialize: toBuffer, responseDeserialize: toString } }; describe('String client and server', function() { var client; var server; before(function() { server = new grpc.Server(); server.addService(string_service_attrs, { capitalize: function(call, callback) { callback(null, _.capitalize(call.request)); } }); var port = server.bind('localhost:0', server_insecure_creds); server.start(); var Client = grpc.makeGenericClientConstructor(string_service_attrs); client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); }); after(function() { server.forceShutdown(); }); it('Should respond with a capitalized string', function(done) { client.capitalize('abc', function(err, response) { assert.ifError(err); assert.strictEqual(response, 'Abc'); done(); }); }); }); }); describe('Echo metadata', function() { var client; var server; var metadata; before(function() { var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto'); var test_service = test_proto.lookup('TestService'); server = new grpc.Server(); server.addProtoService(test_service, { unary: function(call, cb) { call.sendMetadata(call.metadata); cb(null, {}); }, clientStream: function(stream, cb){ stream.on('data', function(data) {}); stream.on('end', function() { stream.sendMetadata(stream.metadata); cb(null, {}); }); }, serverStream: function(stream) { stream.sendMetadata(stream.metadata); stream.end(); }, bidiStream: function(stream) { stream.on('data', function(data) {}); stream.on('end', function() { stream.sendMetadata(stream.metadata); stream.end(); }); } }); var port = server.bind('localhost:0', server_insecure_creds); var Client = surface_client.makeProtobufClientConstructor(test_service); client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); server.start(); metadata = new grpc.Metadata(); metadata.set('key', 'value'); }); after(function() { server.forceShutdown(); }); it('with unary call', function(done) { var call = client.unary({}, function(err, data) { assert.ifError(err); }, metadata); call.on('metadata', function(metadata) { assert.deepEqual(metadata.get('key'), ['value']); done(); }); }); it('with client stream call', function(done) { var call = client.clientStream(function(err, data) { assert.ifError(err); }, metadata); call.on('metadata', function(metadata) { assert.deepEqual(metadata.get('key'), ['value']); done(); }); call.end(); }); it('with server stream call', function(done) { var call = client.serverStream({}, metadata); call.on('data', function() {}); call.on('metadata', function(metadata) { assert.deepEqual(metadata.get('key'), ['value']); done(); }); }); it('with bidi stream call', function(done) { var call = client.bidiStream(metadata); call.on('data', function() {}); call.on('metadata', function(metadata) { assert.deepEqual(metadata.get('key'), ['value']); done(); }); call.end(); }); it('shows the correct user-agent string', function(done) { var version = require('../package.json').version; var call = client.unary({}, function(err, data) { assert.ifError(err); }, metadata); call.on('metadata', function(metadata) { assert(_.startsWith(metadata.get('user-agent')[0], 'grpc-node/' + version)); done(); }); }); }); describe('Other conditions', function() { var test_service; var Client; var client; var server; var port; before(function() { var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto'); test_service = test_proto.lookup('TestService'); server = new grpc.Server(); var trailer_metadata = new grpc.Metadata(); trailer_metadata.add('trailer-present', 'yes'); server.addProtoService(test_service, { unary: function(call, cb) { var req = call.request; if (req.error) { cb(new Error('Requested error'), null, trailer_metadata); } else { cb(null, {count: 1}, trailer_metadata); } }, clientStream: function(stream, cb){ var count = 0; var errored; stream.on('data', function(data) { if (data.error) { errored = true; cb(new Error('Requested error'), null, trailer_metadata); } else { count += 1; } }); stream.on('end', function() { if (!errored) { cb(null, {count: count}, trailer_metadata); } }); }, serverStream: function(stream) { var req = stream.request; if (req.error) { var err = new Error('Requested error'); err.metadata = trailer_metadata; stream.emit('error', err); } else { for (var i = 0; i < 5; i++) { stream.write({count: i}); } stream.end(trailer_metadata); } }, bidiStream: function(stream) { var count = 0; stream.on('data', function(data) { if (data.error) { var err = new Error('Requested error'); err.metadata = trailer_metadata.clone(); err.metadata.add('count', '' + count); stream.emit('error', err); } else { stream.write({count: count}); count += 1; } }); stream.on('end', function() { stream.end(trailer_metadata); }); } }); port = server.bind('localhost:0', server_insecure_creds); Client = surface_client.makeProtobufClientConstructor(test_service); client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); server.start(); }); after(function() { server.forceShutdown(); }); it('channel.getTarget should be available', function() { assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(), 'string'); }); describe('Server recieving bad input', function() { var misbehavingClient; var badArg = new Buffer([0xFF]); before(function() { var test_service_attrs = { unary: { path: '/TestService/Unary', requestStream: false, responseStream: false, requestSerialize: _.identity, responseDeserialize: _.identity }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, requestSerialize: _.identity, responseDeserialize: _.identity }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, requestSerialize: _.identity, responseDeserialize: _.identity }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, requestSerialize: _.identity, responseDeserialize: _.identity } }; var Client = surface_client.makeClientConstructor(test_service_attrs, 'TestService'); misbehavingClient = new Client('localhost:' + port, grpc.Credentials.createInsecure()); }); it('should respond correctly to a unary call', function(done) { misbehavingClient.unary(badArg, function(err, data) { assert(err); assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT); done(); }); }); it('should respond correctly to a client stream', function(done) { var call = misbehavingClient.clientStream(function(err, data) { assert(err); assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT); done(); }); call.write(badArg); // TODO(mlumish): Remove call.end() call.end(); }); it('should respond correctly to a server stream', function(done) { var call = misbehavingClient.serverStream(badArg); call.on('data', function(data) { assert.fail(data, null, 'Unexpected data', '==='); }); call.on('error', function(err) { assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT); done(); }); }); it('should respond correctly to a bidi stream', function(done) { var call = misbehavingClient.bidiStream(); call.on('data', function(data) { assert.fail(data, null, 'Unexpected data', '==='); }); call.on('error', function(err) { assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT); done(); }); call.write(badArg); // TODO(mlumish): Remove call.end() call.end(); }); }); describe('Trailing metadata', function() { it('should be present when a unary call succeeds', function(done) { var call = client.unary({error: false}, function(err, data) { assert.ifError(err); }); call.on('status', function(status) { assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a unary call fails', function(done) { var call = client.unary({error: true}, function(err, data) { assert(err); }); call.on('status', function(status) { assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a client stream call succeeds', function(done) { var call = client.clientStream(function(err, data) { assert.ifError(err); }); call.write({error: false}); call.write({error: false}); call.end(); call.on('status', function(status) { assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a client stream call fails', function(done) { var call = client.clientStream(function(err, data) { assert(err); }); call.write({error: false}); call.write({error: true}); call.end(); call.on('status', function(status) { assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a server stream call succeeds', function(done) { var call = client.serverStream({error: false}); call.on('data', function(){}); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a server stream call fails', function(done) { var call = client.serverStream({error: true}); call.on('data', function(){}); call.on('error', function(error) { assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a bidi stream succeeds', function(done) { var call = client.bidiStream(); call.write({error: false}); call.write({error: false}); call.end(); call.on('data', function(){}); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); done(); }); }); it('should be present when a bidi stream fails', function(done) { var call = client.bidiStream(); call.write({error: false}); call.write({error: true}); call.end(); call.on('data', function(){}); call.on('error', function(error) { assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); done(); }); }); }); describe('Error object should contain the status', function() { it('for a unary call', function(done) { client.unary({error: true}, function(err, data) { assert(err); assert.strictEqual(err.code, grpc.status.UNKNOWN); assert.strictEqual(err.message, 'Requested error'); done(); }); }); it('for a client stream call', function(done) { var call = client.clientStream(function(err, data) { assert(err); assert.strictEqual(err.code, grpc.status.UNKNOWN); assert.strictEqual(err.message, 'Requested error'); done(); }); call.write({error: false}); call.write({error: true}); call.end(); }); it('for a server stream call', function(done) { var call = client.serverStream({error: true}); call.on('data', function(){}); call.on('error', function(error) { assert.strictEqual(error.code, grpc.status.UNKNOWN); assert.strictEqual(error.message, 'Requested error'); done(); }); }); it('for a bidi stream call', function(done) { var call = client.bidiStream(); call.write({error: false}); call.write({error: true}); call.end(); call.on('data', function(){}); call.on('error', function(error) { assert.strictEqual(error.code, grpc.status.UNKNOWN); assert.strictEqual(error.message, 'Requested error'); done(); }); }); }); describe('call.getPeer should return the peer', function() { it('for a unary call', function(done) { var call = client.unary({error: false}, function(err, data) { assert.ifError(err); done(); }); assert.strictEqual(typeof call.getPeer(), 'string'); }); it('for a client stream call', function(done) { var call = client.clientStream(function(err, data) { assert.ifError(err); done(); }); assert.strictEqual(typeof call.getPeer(), 'string'); call.write({error: false}); call.end(); }); it('for a server stream call', function(done) { var call = client.serverStream({error: false}); assert.strictEqual(typeof call.getPeer(), 'string'); call.on('data', function(){}); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); done(); }); }); it('for a bidi stream call', function(done) { var call = client.bidiStream(); assert.strictEqual(typeof call.getPeer(), 'string'); call.write({error: false}); call.end(); call.on('data', function(){}); call.on('status', function(status) { done(); }); }); }); describe('Call propagation', function() { var proxy; var proxy_impl; beforeEach(function() { proxy = new grpc.Server(); proxy_impl = { unary: function(call) {}, clientStream: function(stream) {}, serverStream: function(stream) {}, bidiStream: function(stream) {} }; }); afterEach(function() { console.log('Shutting down server'); proxy.forceShutdown(); }); describe('Cancellation', function() { it('With a unary call', function(done) { done = multiDone(done, 2); proxy_impl.unary = function(parent, callback) { client.unary(parent.request, function(err, value) { try { assert(err); assert.strictEqual(err.code, grpc.status.CANCELLED); } finally { callback(err, value); done(); } }, null, {parent: parent}); call.cancel(); }; proxy.addProtoService(test_service, proxy_impl); var proxy_port = proxy.bind('localhost:0', server_insecure_creds); proxy.start(); var proxy_client = new Client('localhost:' + proxy_port, grpc.Credentials.createInsecure()); var call = proxy_client.unary({}, function(err, value) { done(); }); }); it('With a client stream call', function(done) { done = multiDone(done, 2); proxy_impl.clientStream = function(parent, callback) { client.clientStream(function(err, value) { try { assert(err); assert.strictEqual(err.code, grpc.status.CANCELLED); } finally { callback(err, value); done(); } }, null, {parent: parent}); call.cancel(); }; proxy.addProtoService(test_service, proxy_impl); var proxy_port = proxy.bind('localhost:0', server_insecure_creds); proxy.start(); var proxy_client = new Client('localhost:' + proxy_port, grpc.Credentials.createInsecure()); var call = proxy_client.clientStream(function(err, value) { done(); }); }); it('With a server stream call', function(done) { done = multiDone(done, 2); proxy_impl.serverStream = function(parent) { var child = client.serverStream(parent.request, null, {parent: parent}); child.on('error', function(err) { assert(err); assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); }; proxy.addProtoService(test_service, proxy_impl); var proxy_port = proxy.bind('localhost:0', server_insecure_creds); proxy.start(); var proxy_client = new Client('localhost:' + proxy_port, grpc.Credentials.createInsecure()); var call = proxy_client.serverStream({}); call.on('error', function(err) { done(); }); }); it('With a bidi stream call', function(done) { done = multiDone(done, 2); proxy_impl.bidiStream = function(parent) { var child = client.bidiStream(null, {parent: parent}); child.on('error', function(err) { assert(err); assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); }; proxy.addProtoService(test_service, proxy_impl); var proxy_port = proxy.bind('localhost:0', server_insecure_creds); proxy.start(); var proxy_client = new Client('localhost:' + proxy_port, grpc.Credentials.createInsecure()); var call = proxy_client.bidiStream(); call.on('error', function(err) { done(); }); }); }); describe('Deadline', function() { /* jshint bitwise:false */ var deadline_flags = (grpc.propagate.DEFAULTS & ~grpc.propagate.CANCELLATION); it('With a client stream call', function(done) { done = multiDone(done, 2); proxy_impl.clientStream = function(parent, callback) { client.clientStream(function(err, value) { try { assert(err); assert(err.code === grpc.status.DEADLINE_EXCEEDED || err.code === grpc.status.INTERNAL); } finally { callback(err, value); done(); } }, null, {parent: parent, propagate_flags: deadline_flags}); }; proxy.addProtoService(test_service, proxy_impl); var proxy_port = proxy.bind('localhost:0', server_insecure_creds); proxy.start(); var proxy_client = new Client('localhost:' + proxy_port, grpc.Credentials.createInsecure()); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); proxy_client.clientStream(function(err, value) { done(); }, null, {deadline: deadline}); }); it('With a bidi stream call', function(done) { done = multiDone(done, 2); proxy_impl.bidiStream = function(parent) { var child = client.bidiStream( null, {parent: parent, propagate_flags: deadline_flags}); child.on('error', function(err) { assert(err); assert(err.code === grpc.status.DEADLINE_EXCEEDED || err.code === grpc.status.INTERNAL); done(); }); }; proxy.addProtoService(test_service, proxy_impl); var proxy_port = proxy.bind('localhost:0', server_insecure_creds); proxy.start(); var proxy_client = new Client('localhost:' + proxy_port, grpc.Credentials.createInsecure()); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); var call = proxy_client.bidiStream(null, {deadline: deadline}); call.on('error', function(err) { done(); }); }); }); }); }); describe('Cancelling surface client', function() { var client; var server; before(function() { server = new grpc.Server(); server.addProtoService(mathService, { 'div': function(stream) {}, 'divMany': function(stream) {}, 'fib': function(stream) {}, 'sum': function(stream) {} }); var port = server.bind('localhost:0', server_insecure_creds); var Client = surface_client.makeProtobufClientConstructor(mathService); client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); server.start(); }); after(function() { server.forceShutdown(); }); it('Should correctly cancel a unary call', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { assert.strictEqual(err.code, surface_client.status.CANCELLED); done(); }); call.cancel(); }); it('Should correctly cancel a client stream call', function(done) { var call = client.sum(function(err, resp) { assert.strictEqual(err.code, surface_client.status.CANCELLED); done(); }); call.cancel(); }); it('Should correctly cancel a server stream call', function(done) { var call = client.fib({'limit': 5}); call.on('error', function(error) { assert.strictEqual(error.code, surface_client.status.CANCELLED); done(); }); call.cancel(); }); it('Should correctly cancel a bidi stream call', function(done) { var call = client.divMany(); call.on('error', function(error) { assert.strictEqual(error.code, surface_client.status.CANCELLED); done(); }); call.cancel(); }); }); grpc-0.11.1/src/node/test/call_test.js0000644000175000017500000001577612600663151017742 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var grpc = require('bindings')('grpc.node'); /** * Helper function to return an absolute deadline given a relative timeout in * seconds. * @param {number} timeout_secs The number of seconds to wait before timing out * @return {Date} A date timeout_secs in the future */ function getDeadline(timeout_secs) { var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + timeout_secs); return deadline; } var insecureCreds = grpc.Credentials.createInsecure(); describe('call', function() { var channel; var server; before(function() { server = new grpc.Server(); var port = server.addHttp2Port('localhost:0', grpc.ServerCredentials.createInsecure()); server.start(); channel = new grpc.Channel('localhost:' + port, insecureCreds); }); after(function() { server.forceShutdown(); }); describe('constructor', function() { it('should reject anything less than 3 arguments', function() { assert.throws(function() { new grpc.Call(); }, TypeError); assert.throws(function() { new grpc.Call(channel); }, TypeError); assert.throws(function() { new grpc.Call(channel, 'method'); }, TypeError); }); it('should succeed with a Channel, a string, and a date or number', function() { assert.doesNotThrow(function() { new grpc.Call(channel, 'method', new Date()); }); assert.doesNotThrow(function() { new grpc.Call(channel, 'method', 0); }); }); it('should accept an optional fourth string parameter', function() { assert.doesNotThrow(function() { new grpc.Call(channel, 'method', new Date(), 'host_override'); }); }); it('should fail with a closed channel', function() { var local_channel = new grpc.Channel('hostname', insecureCreds); local_channel.close(); assert.throws(function() { new grpc.Call(channel, 'method'); }); }); it('should fail with other types', function() { assert.throws(function() { new grpc.Call({}, 'method', 0); }, TypeError); assert.throws(function() { new grpc.Call(channel, null, 0); }, TypeError); assert.throws(function() { new grpc.Call(channel, 'method', 'now'); }, TypeError); }); }); describe('startBatch', function() { it('should fail without an object and a function', function() { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.throws(function() { call.startBatch(); }); assert.throws(function() { call.startBatch({}); }); assert.throws(function() { call.startBatch(null, function(){}); }); }); it('should succeed with an empty object', function(done) { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.doesNotThrow(function() { call.startBatch({}, function(err) { assert.ifError(err); done(); }); }); }); }); describe('startBatch with metadata', function() { it('should succeed with a map of strings to string arrays', function(done) { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.doesNotThrow(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'], 'key2': ['value2']}; call.startBatch(batch, function(err, resp) { assert.ifError(err); assert.deepEqual(resp, {'send_metadata': true}); done(); }); }); }); it('should succeed with a map of strings to buffer arrays', function(done) { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.doesNotThrow(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = { 'key1-bin': [new Buffer('value1')], 'key2-bin': [new Buffer('value2')] }; call.startBatch(batch, function(err, resp) { assert.ifError(err); assert.deepEqual(resp, {'send_metadata': true}); done(); }); }); }); it('should fail with other parameter types', function() { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = undefined; call.startBatch(batch, function(){}); }); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = null; call.startBatch(batch, function(){}); }, TypeError); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = 'value'; call.startBatch(batch, function(){}); }, TypeError); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = 5; call.startBatch(batch, function(){}); }, TypeError); }); }); describe('cancel', function() { it('should succeed', function() { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.doesNotThrow(function() { call.cancel(); }); }); }); describe('getPeer', function() { it('should return a string', function() { var call = new grpc.Call(channel, 'method', getDeadline(1)); assert.strictEqual(typeof call.getPeer(), 'string'); }); }); }); grpc-0.11.1/src/node/test/end_to_end_test.js0000644000175000017500000002610312600663151021107 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var grpc = require('bindings')('grpc.node'); /** * This is used for testing functions with multiple asynchronous calls that * can happen in different orders. This should be passed the number of async * function invocations that can occur last, and each of those should call this * function's return value * @param {function()} done The function that should be called when a test is * complete. * @param {number} count The number of calls to the resulting function if the * test passes. * @return {function()} The function that should be called at the end of each * sequence of asynchronous functions. */ function multiDone(done, count) { return function() { count -= 1; if (count <= 0) { done(); } }; } var insecureCreds = grpc.Credentials.createInsecure(); describe('end-to-end', function() { var server; var channel; before(function() { server = new grpc.Server(); var port_num = server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); server.start(); channel = new grpc.Channel('localhost:' + port_num, insecureCreds); }); after(function() { server.forceShutdown(); }); it('should start and end a request without error', function(complete) { var done = multiDone(complete, 2); var status_text = 'xyz'; var call = new grpc.Call(channel, 'dummy_method', Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { send_metadata: true, client_close: true, metadata: {}, status: { code: grpc.status.OK, details: status_text, metadata: {} } }); done(); }); server.requestCall(function(err, call_details) { var new_call = call_details.new_call; assert.notEqual(new_call, null); var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { metadata: {}, code: grpc.status.OK, details: status_text }; server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { send_metadata: true, send_status: true, cancelled: false }); done(); }); }); }); it('should successfully send and receive metadata', function(complete) { var done = multiDone(complete, 2); var status_text = 'xyz'; var call = new grpc.Call(channel, 'dummy_method', Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = { client_key: ['client_value'] }; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response,{ send_metadata: true, client_close: true, metadata: {server_key: ['server_value']}, status: {code: grpc.status.OK, details: status_text, metadata: {}} }); done(); }); server.requestCall(function(err, call_details) { var new_call = call_details.new_call; assert.notEqual(new_call, null); assert.strictEqual(new_call.metadata.client_key[0], 'client_value'); var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = { server_key: ['server_value'] }; server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { metadata: {}, code: grpc.status.OK, details: status_text }; server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { send_metadata: true, send_status: true, cancelled: false }); done(); }); }); }); it('should send and receive data without error', function(complete) { var req_text = 'client_request'; var reply_text = 'server_response'; var done = multiDone(complete, 2); var status_text = 'success'; var call = new grpc.Call(channel, 'dummy_method', Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(req_text); client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_MESSAGE] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert(response.send_metadata); assert(response.client_close); assert.deepEqual(response.metadata, {}); assert(response.send_message); assert.strictEqual(response.read.toString(), reply_text); assert.deepEqual(response.status, {code: grpc.status.OK, details: status_text, metadata: {}}); done(); }); server.requestCall(function(err, call_details) { var new_call = call_details.new_call; assert.notEqual(new_call, null); var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; server_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); assert(response.send_metadata); assert.strictEqual(response.read.toString(), req_text); var response_batch = {}; response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text); response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { metadata: {}, code: grpc.status.OK, details: status_text }; response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; server_call.startBatch(response_batch, function(err, response) { assert(response.send_status); assert(!response.cancelled); done(); }); }); }); }); it('should send multiple messages', function(complete) { var done = multiDone(complete, 2); var requests = ['req1', 'req2']; var status_text = 'xyz'; var call = new grpc.Call(channel, 'dummy_method', Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[0]); client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { send_metadata: true, send_message: true, metadata: {} }); var req2_batch = {}; req2_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[1]); req2_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; req2_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(req2_batch, function(err, resp) { assert.ifError(err); assert.deepEqual(resp, { send_message: true, client_close: true, status: { code: grpc.status.OK, details: status_text, metadata: {} } }); done(); }); }); server.requestCall(function(err, call_details) { var new_call = call_details.new_call; assert.notEqual(new_call, null); var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; server_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); assert(response.send_metadata); assert.strictEqual(response.read.toString(), requests[0]); var snd_batch = {}; snd_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(snd_batch, function(err, response) { assert.ifError(err); assert.strictEqual(response.read.toString(), requests[1]); var end_batch = {}; end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { metadata: {}, code: grpc.status.OK, details: status_text }; server_call.startBatch(end_batch, function(err, response) { assert.ifError(err); assert(response.send_status); assert(!response.cancelled); done(); }); }); }); }); }); }); grpc-0.11.1/src/node/test/channel_test.js0000644000175000017500000001520112600663151020416 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var grpc = require('bindings')('grpc.node'); /** * This is used for testing functions with multiple asynchronous calls that * can happen in different orders. This should be passed the number of async * function invocations that can occur last, and each of those should call this * function's return value * @param {function()} done The function that should be called when a test is * complete. * @param {number} count The number of calls to the resulting function if the * test passes. * @return {function()} The function that should be called at the end of each * sequence of asynchronous functions. */ function multiDone(done, count) { return function() { count -= 1; if (count <= 0) { done(); } }; } var insecureCreds = grpc.Credentials.createInsecure(); describe('channel', function() { describe('constructor', function() { it('should require a string for the first argument', function() { assert.doesNotThrow(function() { new grpc.Channel('hostname', insecureCreds); }); assert.throws(function() { new grpc.Channel(); }, TypeError); assert.throws(function() { new grpc.Channel(5); }); }); it('should require a credential for the second argument', function() { assert.doesNotThrow(function() { new grpc.Channel('hostname', insecureCreds); }); assert.throws(function() { new grpc.Channel('hostname', 5); }); assert.throws(function() { new grpc.Channel('hostname'); }); }); it('should accept an object for the third argument', function() { assert.doesNotThrow(function() { new grpc.Channel('hostname', insecureCreds, {}); }); assert.throws(function() { new grpc.Channel('hostname', insecureCreds, 'abc'); }); }); it('should only accept objects with string or int values', function() { assert.doesNotThrow(function() { new grpc.Channel('hostname', insecureCreds,{'key' : 'value'}); }); assert.doesNotThrow(function() { new grpc.Channel('hostname', insecureCreds, {'key' : 5}); }); assert.throws(function() { new grpc.Channel('hostname', insecureCreds, {'key' : null}); }); assert.throws(function() { new grpc.Channel('hostname', insecureCreds, {'key' : new Date()}); }); }); }); describe('close', function() { var channel; beforeEach(function() { channel = new grpc.Channel('hostname', insecureCreds, {}); }); it('should succeed silently', function() { assert.doesNotThrow(function() { channel.close(); }); }); it('should be idempotent', function() { assert.doesNotThrow(function() { channel.close(); channel.close(); }); }); }); describe('getTarget', function() { var channel; beforeEach(function() { channel = new grpc.Channel('hostname', insecureCreds, {}); }); it('should return a string', function() { assert.strictEqual(typeof channel.getTarget(), 'string'); }); }); describe('getConnectivityState', function() { var channel; beforeEach(function() { channel = new grpc.Channel('hostname', insecureCreds, {}); }); it('should return IDLE for a new channel', function() { assert.strictEqual(channel.getConnectivityState(), grpc.connectivityState.IDLE); }); }); describe('watchConnectivityState', function() { var channel; beforeEach(function() { channel = new grpc.Channel('localhost', insecureCreds, {}); }); afterEach(function() { channel.close(); }); it('should time out if called alone', function(done) { var old_state = channel.getConnectivityState(); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); channel.watchConnectivityState(old_state, deadline, function(err, value) { assert(err); done(); }); }); it('should complete if a connection attempt is forced', function(done) { var old_state = channel.getConnectivityState(); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); channel.watchConnectivityState(old_state, deadline, function(err, value) { assert.ifError(err); assert.notEqual(value.new_state, old_state); done(); }); channel.getConnectivityState(true); }); it('should complete twice if called twice', function(done) { done = multiDone(done, 2); var old_state = channel.getConnectivityState(); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); channel.watchConnectivityState(old_state, deadline, function(err, value) { assert.ifError(err); assert.notEqual(value.new_state, old_state); done(); }); channel.watchConnectivityState(old_state, deadline, function(err, value) { assert.ifError(err); assert.notEqual(value.new_state, old_state); done(); }); channel.getConnectivityState(true); }); }); }); grpc-0.11.1/src/node/test/math_client_test.js0000644000175000017500000001117112600663151021277 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var grpc = require('..'); var math = grpc.load(__dirname + '/../examples/math.proto').math; /** * Client to use to make requests to a running server. */ var math_client; /** * Server to test against */ var server = require('../examples/math_server.js'); describe('Math client', function() { before(function(done) { var port_num = server.bind('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); server.start(); math_client = new math.Math('localhost:' + port_num, grpc.Credentials.createInsecure()); done(); }); after(function() { server.forceShutdown(); }); it('should handle a single request', function(done) { var arg = {dividend: 7, divisor: 4}; math_client.div(arg, function handleDivResult(err, value) { assert.ifError(err); assert.equal(value.quotient, 1); assert.equal(value.remainder, 3); done(); }); }); it('should handle an error from a unary request', function(done) { var arg = {dividend: 7, divisor: 0}; math_client.div(arg, function handleDivResult(err, value) { assert(err); done(); }); }); it('should handle a server streaming request', function(done) { var call = math_client.fib({limit: 7}); var expected_results = [1, 1, 2, 3, 5, 8, 13]; var next_expected = 0; call.on('data', function checkResponse(value) { assert.equal(value.num, expected_results[next_expected]); next_expected += 1; }); call.on('status', function checkStatus(status) { assert.strictEqual(status.code, grpc.status.OK); done(); }); }); it('should handle a client streaming request', function(done) { var call = math_client.sum(function handleSumResult(err, value) { assert.ifError(err); assert.equal(value.num, 21); }); for (var i = 0; i < 7; i++) { call.write({'num': i}); } call.end(); call.on('status', function checkStatus(status) { assert.strictEqual(status.code, grpc.status.OK); done(); }); }); it('should handle a bidirectional streaming request', function(done) { function checkResponse(index, value) { assert.equal(value.quotient, index); assert.equal(value.remainder, 1); } var call = math_client.divMany(); var response_index = 0; call.on('data', function(value) { checkResponse(response_index, value); response_index += 1; }); for (var i = 0; i < 7; i++) { call.write({dividend: 2 * i + 1, divisor: 2}); } call.end(); call.on('status', function checkStatus(status) { assert.strictEqual(status.code, grpc.status.OK); done(); }); }); it('should handle an error from a bidi request', function(done) { var call = math_client.divMany(); call.on('data', function(value) { assert.fail(value, undefined, 'Unexpected data response on failing call', '!='); }); call.write({dividend: 7, divisor: 0}); call.end(); call.on('error', function checkStatus(status) { done(); }); }); }); grpc-0.11.1/src/node/test/data/0000755000175000017500000000000012600663151016323 5ustar apollockapollockgrpc-0.11.1/src/node/test/data/server1.pem0000644000175000017500000000170412600663151020417 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= -----END CERTIFICATE----- grpc-0.11.1/src/node/test/data/ca.pem0000644000175000017500000000152712600663151017416 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 +L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG Dfcog5wrJytaQ6UA0wE= -----END CERTIFICATE----- grpc-0.11.1/src/node/test/data/README0000644000175000017500000000002112600663151017174 0ustar apollockapollockCONFIRMEDTESTKEY grpc-0.11.1/src/node/test/data/server1.key0000644000175000017500000000162012600663151020423 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf 3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR 81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe F98XJ7tIFfJq -----END PRIVATE KEY----- grpc-0.11.1/src/node/test/server_test.js0000644000175000017500000001077212600663151020324 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var fs = require('fs'); var path = require('path'); var grpc = require('bindings')('grpc.node'); describe('server', function() { describe('constructor', function() { it('should work with no arguments', function() { assert.doesNotThrow(function() { new grpc.Server(); }); }); it('should work with an empty list argument', function() { assert.doesNotThrow(function() { new grpc.Server([]); }); }); }); describe('addHttp2Port', function() { var server; before(function() { server = new grpc.Server(); }); it('should bind to an unused port', function() { var port; assert.doesNotThrow(function() { port = server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); }); assert(port > 0); }); it('should bind to an unused port with ssl credentials', function() { var port; var key_path = path.join(__dirname, '../test/data/server1.key'); var pem_path = path.join(__dirname, '../test/data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); var creds = grpc.ServerCredentials.createSsl(null, [{private_key: key_data, cert_chain: pem_data}]); assert.doesNotThrow(function() { port = server.addHttp2Port('0.0.0.0:0', creds); }); assert(port > 0); }); }); describe('addSecureHttp2Port', function() { var server; before(function() { server = new grpc.Server(); }); }); describe('start', function() { var server; before(function() { server = new grpc.Server(); server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); }); after(function() { server.forceShutdown(); }); it('should start without error', function() { assert.doesNotThrow(function() { server.start(); }); }); }); describe('shutdown', function() { var server; beforeEach(function() { server = new grpc.Server(); server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); server.start(); }); afterEach(function() { server.forceShutdown(); }); it('tryShutdown should shutdown successfully', function(done) { server.tryShutdown(done); }); it('forceShutdown should shutdown successfully', function() { server.forceShutdown(); }); it('tryShutdown should be idempotent', function(done) { server.tryShutdown(done); server.tryShutdown(function() {}); }); it('forceShutdown should be idempotent', function() { server.forceShutdown(); server.forceShutdown(); }); it('forceShutdown should trigger tryShutdown', function(done) { server.tryShutdown(done); server.forceShutdown(); }); }); }); grpc-0.11.1/src/node/test/constant_test.js0000644000175000017500000000732412600663151020646 0ustar apollockapollock/* * * 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. * */ 'use strict'; var assert = require('assert'); var grpc = require('bindings')('grpc.node'); /** * List of all status names * @const * @type {Array.} */ var statusNames = [ 'OK', 'CANCELLED', 'UNKNOWN', 'INVALID_ARGUMENT', 'DEADLINE_EXCEEDED', 'NOT_FOUND', 'ALREADY_EXISTS', 'PERMISSION_DENIED', 'UNAUTHENTICATED', 'RESOURCE_EXHAUSTED', 'FAILED_PRECONDITION', 'ABORTED', 'OUT_OF_RANGE', 'UNIMPLEMENTED', 'INTERNAL', 'UNAVAILABLE', 'DATA_LOSS' ]; /** * List of all call error names * @const * @type {Array.} */ var callErrorNames = [ 'OK', 'ERROR', 'NOT_ON_SERVER', 'NOT_ON_CLIENT', 'ALREADY_INVOKED', 'NOT_INVOKED', 'ALREADY_FINISHED', 'TOO_MANY_OPERATIONS', 'INVALID_FLAGS' ]; /** * List of all propagate flag names * @const * @type {Array.} */ var propagateFlagNames = [ 'DEADLINE', 'CENSUS_STATS_CONTEXT', 'CENSUS_TRACING_CONTEXT', 'CANCELLATION', 'DEFAULTS' ]; /* * List of all connectivity state names * @const * @type {Array.} */ var connectivityStateNames = [ 'IDLE', 'CONNECTING', 'READY', 'TRANSIENT_FAILURE', 'FATAL_FAILURE' ]; describe('constants', function() { it('should have all of the status constants', function() { for (var i = 0; i < statusNames.length; i++) { assert(grpc.status.hasOwnProperty(statusNames[i]), 'status missing: ' + statusNames[i]); } }); it('should have all of the call errors', function() { for (var i = 0; i < callErrorNames.length; i++) { assert(grpc.callError.hasOwnProperty(callErrorNames[i]), 'call error missing: ' + callErrorNames[i]); } }); it('should have all of the propagate flags', function() { for (var i = 0; i < propagateFlagNames.length; i++) { assert(grpc.propagate.hasOwnProperty(propagateFlagNames[i]), 'call error missing: ' + propagateFlagNames[i]); } }); it('should have all of the connectivity states', function() { for (var i = 0; i < connectivityStateNames.length; i++) { assert(grpc.connectivityState.hasOwnProperty(connectivityStateNames[i]), 'connectivity status missing: ' + connectivityStateNames[i]); } }); }); grpc-0.11.1/src/node/binding.gyp0000644000175000017500000000416212600663151016571 0ustar apollockapollock{ "targets" : [ { 'include_dirs': [ "/dev/null 2>&1 && echo true || echo false)' }, 'conditions': [ ['pkg_config_grpc == "true"', { 'link_settings': { 'libraries': [ '= iterations) { testServer.server.shutdown(); var totalDiff = process.hrtime(start); finish({ total: totalDiff[0] * 1000000 + totalDiff[1] / 1000, intervals: intervals }); } else{ var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 3); var startTime = process.hrtime(); client.emptyCall({}, function(err, resp) { var timeDiff = process.hrtime(startTime); intervals[i] = timeDiff[0] * 1000000 + timeDiff[1] / 1000; next(i+1); }, {}, {deadline: deadline}); } } next(0); } function warmUp(num) { var pending = num; function startCall() { client.emptyCall({}, function(err, resp) { pending--; if (pending === 0) { runIterations(callback); } }); } for (var i = 0; i < num; i++) { startCall(); } } warmUp(100); } function percentile(arr, pct) { if (pct > 99) { pct = 99; } if (pct < 0) { pct = 0; } var index = Math.floor(arr.length * pct / 100); return arr[index]; } if (require.main === module) { var count; if (process.argv.length >= 3) { count = process.argv[2]; } else { count = 100; } runTest(count, function(results) { var sorted_intervals = _.sortBy(results.intervals, _.identity); console.log('count:', count); console.log('total time:', results.total, 'us'); console.log('median:', percentile(sorted_intervals, 50), 'us'); console.log('90th percentile:', percentile(sorted_intervals, 90), 'us'); console.log('95th percentile:', percentile(sorted_intervals, 95), 'us'); console.log('99th percentile:', percentile(sorted_intervals, 99), 'us'); console.log('QPS:', (count / results.total) * 1000000); }); } module.exports = runTest; grpc-0.11.1/src/node/examples/math.proto0000644000175000017500000000531512600663151020273 0ustar apollockapollock // 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. syntax = "proto3"; package math; message DivArgs { int64 dividend = 1; int64 divisor = 2; } message DivReply { int64 quotient = 1; int64 remainder = 2; } message FibArgs { int64 limit = 1; } message Num { int64 num = 1; } message FibReply { int64 count = 1; } service Math { // Div divides args.dividend by args.divisor and returns the quotient and // remainder. rpc Div (DivArgs) returns (DivReply) { } // DivMany accepts an arbitrary number of division args from the client stream // and sends back the results in the reply stream. The stream continues until // the client closes its end; the server does the same after sending all the // replies. The stream ends immediately if either end aborts. rpc DivMany (stream DivArgs) returns (stream DivReply) { } // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib // generates up to limit numbers; otherwise it continues until the call is // canceled. Unlike Fib above, Fib has no final FibReply. rpc Fib (FibArgs) returns (stream Num) { } // Sum sums a stream of numbers, returning the final result once the stream // is closed. rpc Sum (stream Num) returns (Num) { } } grpc-0.11.1/src/node/examples/stock_server.js0000644000175000017500000000557712600663151021336 0ustar apollockapollock/* * * 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. * */ 'use strict'; var _ = require('lodash'); var grpc = require('..'); var examples = grpc.load(__dirname + '/stock.proto').examples; function getLastTradePrice(call, callback) { callback(null, {symbol: call.request.symbol, price: 88}); } function watchFutureTrades(call) { for (var i = 0; i < call.request.num_trades_to_watch; i++) { call.write({price: 88.00 + i * 10.00}); } call.end(); } function getHighestTradePrice(call, callback) { var trades = []; call.on('data', function(data) { trades.push({symbol: data.symbol, price: _.random(0, 100)}); }); call.on('end', function() { if(_.isEmpty(trades)) { callback(null, {}); } else { callback(null, _.max(trades, function(trade){return trade.price;})); } }); } function getLastTradePriceMultiple(call) { call.on('data', function(data) { call.write({price: 88}); }); call.on('end', function() { call.end(); }); } var stockServer = new grpc.Server(); stockServer.addProtoService(examples.Stock.service, { getLastTradePrice: getLastTradePrice, getLastTradePriceMultiple: getLastTradePriceMultiple, watchFutureTrades: watchFutureTrades, getHighestTradePrice: getHighestTradePrice }); if (require.main === module) { stockServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); stockServer.start(); } module.exports = stockServer; grpc-0.11.1/src/node/examples/qps_test.js0000644000175000017500000001133412600663151020453 0ustar apollockapollock/* * * 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. * */ /** * This script runs a QPS test. It sends requests for a specified length of time * with a specified number pending at any one time. It then outputs the measured * QPS. Usage: * node qps_test.js [--concurrent=count] [--time=seconds] * concurrent defaults to 100 and time defaults to 10 */ 'use strict'; var async = require('async'); var parseArgs = require('minimist'); var grpc = require('..'); var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing; var interop_server = require('../interop/interop_server.js'); /** * Runs the QPS test. Sends requests constantly for the given number of seconds, * and keeps concurrent_calls requests pending at all times. When the test ends, * the callback is called with the number of calls that completed within the * time limit. * @param {number} concurrent_calls The number of calls to have pending * simultaneously * @param {number} seconds The number of seconds to run the test for * @param {function(Error, number)} callback Callback for test completion */ function runTest(concurrent_calls, seconds, callback) { var testServer = interop_server.getServer(0, false); testServer.server.start(); var client = new testProto.TestService('localhost:' + testServer.port, grpc.Credentials.createInsecure()); var warmup_num = 100; /** * Warms up the client to avoid counting startup time in the test result * @param {function(Error)} callback Called when warmup is complete */ function warmUp(callback) { var pending = warmup_num; function startCall() { client.emptyCall({}, function(err, resp) { if (err) { callback(err); return; } pending--; if (pending === 0) { callback(null); } }); } for (var i = 0; i < warmup_num; i++) { startCall(); } } /** * Run the QPS test. Starts concurrent_calls requests, then starts a new * request whenever one completes until time runs out. * @param {function(Error, number)} callback Called when the test is complete. * The second argument is the number of calls that finished within the * time limit */ function run(callback) { var running = 0; var count = 0; var start = process.hrtime(); function responseCallback(err, resp) { if (process.hrtime(start)[0] < seconds) { count += 1; client.emptyCall({}, responseCallback); } else { running -= 1; if (running <= 0) { callback(null, count); } } } for (var i = 0; i < concurrent_calls; i++) { running += 1; client.emptyCall({}, responseCallback); } } async.waterfall([warmUp, run], function(err, count) { testServer.server.shutdown(); callback(err, count); }); } if (require.main === module) { var argv = parseArgs(process.argv.slice(2), { default: {'concurrent': 100, 'time': 10} }); runTest(argv.concurrent, argv.time, function(err, count) { if (err) { throw err; } console.log('Concurrent calls:', argv.concurrent); console.log('Time:', argv.time, 'seconds'); console.log('QPS:', (count/argv.time)); }); } grpc-0.11.1/src/node/examples/stock_client.js0000644000175000017500000000404312600663151021271 0ustar apollockapollock/* * * 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 grpc = require('..'); var examples = grpc.load(__dirname + '/stock.proto').examples; /** * This exports a client constructor for the Stock service. The usage looks like * * var StockClient = require('stock_client.js'); * var stockClient = new StockClient(server_address, * grpc.Credentials.createInsecure()); * stockClient.getLastTradePrice({symbol: 'GOOG'}, function(error, response) { * console.log(error || response); * }); */ module.exports = examples.Stock; grpc-0.11.1/src/node/interop/0000755000175000017500000000000012600663151016113 5ustar apollockapollockgrpc-0.11.1/src/node/interop/empty.proto0000644000175000017500000000360312600663151020340 0ustar apollockapollock // 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. syntax = "proto3"; package grpc.testing; // An empty message that you can re-use to avoid defining duplicated empty // messages in your project. A typical example is to use it as argument or the // return value of a service API. For instance: // // service Foo { // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; // }; // message Empty {} grpc-0.11.1/src/node/interop/test.proto0000644000175000017500000000644112600663151020164 0ustar apollockapollock // 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. // An integration test service that covers all the method signature permutations // of unary/streaming requests/responses. syntax = "proto3"; import "empty.proto"; import "messages.proto"; package grpc.testing; // A simple service to test the various types of RPCs and experiment with // performance with various types of payload. service TestService { // One empty request followed by one empty response. rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); // One request followed by one response. // TODO(Issue 527): Describe required server behavior. rpc UnaryCall(SimpleRequest) returns (SimpleResponse); // One request followed by a sequence of responses (streamed download). // The server returns the payload with client desired type and sizes. rpc StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); // A sequence of requests followed by one response (streamed upload). // The server returns the aggregated size of client payload as the result. rpc StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse); // A sequence of requests with each request served by the server immediately. // As one request could lead to multiple responses, this interface // demonstrates the idea of full duplexing. rpc FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); // A sequence of requests followed by a sequence of responses. // The server buffers all the client requests and then serves them in order. A // stream of responses are returned to the client when the server starts with // first request. rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); } grpc-0.11.1/src/node/interop/interop_client.js0000644000175000017500000003147512600663151021501 0ustar apollockapollock/* * * 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. * */ 'use strict'; var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var grpc = require('..'); var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; var GoogleAuth = require('google-auth-library'); var assert = require('assert'); var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo'; var AUTH_SCOPE_RESPONSE = 'xapi.zoo'; var AUTH_USER = ('155450119199-vefjjaekcc6cmsd5914v6lqufunmh9ue' + '@developer.gserviceaccount.com'); var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' + '@developer.gserviceaccount.com'); /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer * @return {Buffer} The new buffer */ function zeroBuffer(size) { var zeros = new Buffer(size); zeros.fill(0); return zeros; } /** * Run the empty_unary test * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function emptyUnary(client, done) { client.emptyCall({}, function(err, resp) { assert.ifError(err); if (done) { done(); } }); } /** * Run the large_unary test * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function largeUnary(client, done) { var arg = { response_type: 'COMPRESSABLE', response_size: 314159, payload: { body: zeroBuffer(271828) } }; client.unaryCall(arg, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); assert.strictEqual(resp.payload.body.length, 314159); if (done) { done(); } }); } /** * Run the client_streaming test * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function clientStreaming(client, done) { var call = client.streamingInputCall(function(err, resp) { assert.ifError(err); assert.strictEqual(resp.aggregated_payload_size, 74922); if (done) { done(); } }); var payload_sizes = [27182, 8, 1828, 45904]; for (var i = 0; i < payload_sizes.length; i++) { call.write({payload: {body: zeroBuffer(payload_sizes[i])}}); } call.end(); } /** * Run the server_streaming test * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function serverStreaming(client, done) { var arg = { response_type: 'COMPRESSABLE', response_parameters: [ {size: 31415}, {size: 9}, {size: 2653}, {size: 58979} ] }; var call = client.streamingOutputCall(arg); var resp_index = 0; call.on('data', function(value) { assert(resp_index < 4); assert.strictEqual(value.payload.type, 'COMPRESSABLE'); assert.strictEqual(value.payload.body.length, arg.response_parameters[resp_index].size); resp_index += 1; }); call.on('end', function() { assert.strictEqual(resp_index, 4); if (done) { done(); } }); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); }); } /** * Run the ping_pong test * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function pingPong(client, done) { var payload_sizes = [27182, 8, 1828, 45904]; var response_sizes = [31415, 9, 2653, 58979]; var call = client.fullDuplexCall(); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } }); var index = 0; call.write({ response_type: 'COMPRESSABLE', response_parameters: [ {size: response_sizes[index]} ], payload: {body: zeroBuffer(payload_sizes[index])} }); call.on('data', function(response) { assert.strictEqual(response.payload.type, 'COMPRESSABLE'); assert.equal(response.payload.body.length, response_sizes[index]); index += 1; if (index === 4) { call.end(); } else { call.write({ response_type: 'COMPRESSABLE', response_parameters: [ {size: response_sizes[index]} ], payload: {body: zeroBuffer(payload_sizes[index])} }); } }); } /** * Run the empty_stream test. * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function emptyStream(client, done) { var call = client.fullDuplexCall(); call.on('status', function(status) { assert.strictEqual(status.code, grpc.status.OK); if (done) { done(); } }); call.on('data', function(value) { assert.fail(value, null, 'No data should have been received', '!=='); }); call.end(); } /** * Run the cancel_after_begin test. * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function cancelAfterBegin(client, done) { var call = client.streamingInputCall(function(err, resp) { assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); } /** * Run the cancel_after_first_response test. * @param {Client} client The client to test against * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function cancelAfterFirstResponse(client, done) { var call = client.fullDuplexCall(); call.write({ response_type: 'COMPRESSABLE', response_parameters: [ {size: 31415} ], payload: {body: zeroBuffer(27182)} }); call.on('data', function(data) { call.cancel(); }); call.on('error', function(error) { assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); } function timeoutOnSleepingServer(client, done) { var deadline = new Date(); deadline.setMilliseconds(deadline.getMilliseconds() + 1); var call = client.fullDuplexCall(null, {deadline: deadline}); call.write({ payload: {body: zeroBuffer(27182)} }); call.on('error', function(error) { assert(error.code === grpc.status.DEADLINE_EXCEEDED || error.code === grpc.status.INTERNAL); done(); }); } /** * Run one of the authentication tests. * @param {string} expected_user The expected username in the response * @param {Client} client The client to test against * @param {?string} scope The scope to apply to the credentials * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function authTest(expected_user, scope, client, done) { (new GoogleAuth()).getApplicationDefault(function(err, credential) { assert.ifError(err); if (credential.createScopedRequired() && scope) { credential = credential.createScoped(scope); } client.$updateMetadata = grpc.getGoogleAuthDelegate(credential); var arg = { response_type: 'COMPRESSABLE', response_size: 314159, payload: { body: zeroBuffer(271828) }, fill_username: true, fill_oauth_scope: true }; client.unaryCall(arg, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); assert.strictEqual(resp.payload.body.length, 314159); assert.strictEqual(resp.username, expected_user); if (scope) { assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); } if (done) { done(); } }); }); } function oauth2Test(expected_user, scope, per_rpc, client, done) { (new GoogleAuth()).getApplicationDefault(function(err, credential) { assert.ifError(err); var arg = { fill_username: true, fill_oauth_scope: true }; credential = credential.createScoped(scope); credential.getAccessToken(function(err, token) { assert.ifError(err); var updateMetadata = function(authURI, metadata, callback) { metadata.add('authorization', 'Bearer ' + token); callback(null, metadata); }; var makeTestCall = function(error, client_metadata) { assert.ifError(error); client.unaryCall(arg, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.username, expected_user); assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); if (done) { done(); } }, client_metadata); }; if (per_rpc) { updateMetadata('', new grpc.Metadata(), makeTestCall); } else { client.$updateMetadata = updateMetadata; makeTestCall(null, new grpc.Metadata()); } }); }); } /** * Map from test case names to test functions */ var test_cases = { empty_unary: emptyUnary, large_unary: largeUnary, client_streaming: clientStreaming, server_streaming: serverStreaming, ping_pong: pingPong, empty_stream: emptyStream, cancel_after_begin: cancelAfterBegin, cancel_after_first_response: cancelAfterFirstResponse, timeout_on_sleeping_server: timeoutOnSleepingServer, compute_engine_creds: _.partial(authTest, COMPUTE_ENGINE_USER, null), service_account_creds: _.partial(authTest, AUTH_USER, AUTH_SCOPE), jwt_token_creds: _.partial(authTest, AUTH_USER, null), oauth2_auth_token: _.partial(oauth2Test, AUTH_USER, AUTH_SCOPE, false), per_rpc_creds: _.partial(oauth2Test, AUTH_USER, AUTH_SCOPE, true) }; /** * Execute a single test case. * @param {string} address The address of the server to connect to, in the * format 'hostname:port' * @param {string} host_overrirde The hostname of the server to use as an SSL * override * @param {string} test_case The name of the test case to run * @param {bool} tls Indicates that a secure channel should be used * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha */ function runTest(address, host_override, test_case, tls, test_ca, done) { // TODO(mlumish): enable TLS functionality var options = {}; var creds; if (tls) { var ca_path; if (test_ca) { ca_path = path.join(__dirname, '../test/data/ca.pem'); } else { ca_path = process.env.SSL_CERT_FILE; } var ca_data = fs.readFileSync(ca_path); creds = grpc.Credentials.createSsl(ca_data); if (host_override) { options['grpc.ssl_target_name_override'] = host_override; options['grpc.default_authority'] = host_override; } } else { creds = grpc.Credentials.createInsecure(); } var client = new testProto.TestService(address, creds, options); test_cases[test_case](client, done); } if (require.main === module) { var parseArgs = require('minimist'); var argv = parseArgs(process.argv, { string: ['server_host', 'server_host_override', 'server_port', 'test_case', 'use_tls', 'use_test_ca'] }); runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', function () { console.log('OK:', argv.test_case); }); } /** * See docs for runTest */ exports.runTest = runTest; grpc-0.11.1/src/node/interop/messages.proto0000644000175000017500000001062112600663151021007 0ustar apollockapollock // 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. // Message definitions to be used by integration test service definitions. syntax = "proto3"; package grpc.testing; // The type of payload that should be returned. enum PayloadType { // Compressable text format. COMPRESSABLE = 0; // Uncompressable binary format. UNCOMPRESSABLE = 1; // Randomly chosen from all other formats defined in this enum. RANDOM = 2; } // A block of data, to simply increase gRPC message size. message Payload { // The type of data in body. PayloadType type = 1; // Primary contents of payload. bytes body = 2; } // Unary request. message SimpleRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, server randomly chooses one from other formats. PayloadType response_type = 1; // Desired payload size in the response from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. int32 response_size = 2; // Optional input payload sent along with the request. Payload payload = 3; // Whether SimpleResponse should include username. bool fill_username = 4; // Whether SimpleResponse should include OAuth scope. bool fill_oauth_scope = 5; } // Unary response, as configured by the request. message SimpleResponse { // Payload to increase message size. Payload payload = 1; // The user the request came from, for verifying authentication was // successful when the client expected it. string username = 2; // OAuth scope. string oauth_scope = 3; } // Client-streaming request. message StreamingInputCallRequest { // Optional input payload sent along with the request. Payload payload = 1; // Not expecting any payload from the response. } // Client-streaming response. message StreamingInputCallResponse { // Aggregated size of payloads received from the client. int32 aggregated_payload_size = 1; } // Configuration for a particular response. message ResponseParameters { // Desired payload sizes in responses from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. int32 size = 1; // Desired interval between consecutive responses in the response stream in // microseconds. int32 interval_us = 2; } // Server-streaming request. message StreamingOutputCallRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, the payload from each response in the stream // might be of different types. This is to simulate a mixed type of payload // stream. PayloadType response_type = 1; // Configuration for each expected response message. repeated ResponseParameters response_parameters = 2; // Optional input payload sent along with the request. Payload payload = 3; } // Server-streaming response, as configured by the request and parameters. message StreamingOutputCallResponse { // Payload to increase response size. Payload payload = 1; } grpc-0.11.1/src/node/interop/interop_server.js0000644000175000017500000001464612600663151021532 0ustar apollockapollock/* * * 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. * */ 'use strict'; var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var grpc = require('..'); var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer * @return {Buffer} The new buffer */ function zeroBuffer(size) { var zeros = new Buffer(size); zeros.fill(0); return zeros; } /** * Respond to an empty parameter with an empty response. * NOTE: this currently does not work due to issue #137 * @param {Call} call Call to handle * @param {function(Error, Object)} callback Callback to call with result * or error */ function handleEmpty(call, callback) { callback(null, {}); } /** * Handle a unary request by sending the requested payload * @param {Call} call Call to handle * @param {function(Error, Object)} callback Callback to call with result or * error */ function handleUnary(call, callback) { var req = call.request; var zeros = zeroBuffer(req.response_size); var payload_type = req.response_type; if (payload_type === 'RANDOM') { payload_type = ['COMPRESSABLE', 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; } callback(null, {payload: {type: payload_type, body: zeros}}); } /** * Respond to a streaming call with the total size of all payloads * @param {Call} call Call to handle * @param {function(Error, Object)} callback Callback to call with result or * error */ function handleStreamingInput(call, callback) { var aggregate_size = 0; call.on('data', function(value) { aggregate_size += value.payload.body.length; }); call.on('end', function() { callback(null, {aggregated_payload_size: aggregate_size}); }); } /** * Respond to a payload request with a stream of the requested payloads * @param {Call} call Call to handle */ function handleStreamingOutput(call) { var req = call.request; var payload_type = req.response_type; if (payload_type === 'RANDOM') { payload_type = ['COMPRESSABLE', 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; } _.each(req.response_parameters, function(resp_param) { call.write({ payload: { body: zeroBuffer(resp_param.size), type: payload_type } }); }); call.end(); } /** * Respond to a stream of payload requests with a stream of payload responses as * they arrive. * @param {Call} call Call to handle */ function handleFullDuplex(call) { call.on('data', function(value) { var payload_type = value.response_type; if (payload_type === 'RANDOM') { payload_type = ['COMPRESSABLE', 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; } _.each(value.response_parameters, function(resp_param) { call.write({ payload: { body: zeroBuffer(resp_param.size), type: payload_type } }); }); }); call.on('end', function() { call.end(); }); } /** * Respond to a stream of payload requests with a stream of payload responses * after all requests have arrived * @param {Call} call Call to handle */ function handleHalfDuplex(call) { throw new Error('HalfDuplexCall not yet implemented'); } /** * Get a server object bound to the given port * @param {string} port Port to which to bind * @param {boolean} tls Indicates that the bound port should use TLS * @return {{server: Server, port: number}} Server object bound to the support, * and port number that the server is bound to */ function getServer(port, tls) { // TODO(mlumish): enable TLS functionality var options = {}; var server_creds; if (tls) { var key_path = path.join(__dirname, '../test/data/server1.key'); var pem_path = path.join(__dirname, '../test/data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); server_creds = grpc.ServerCredentials.createSsl(null, [{private_key: key_data, cert_chain: pem_data}]); } else { server_creds = grpc.ServerCredentials.createInsecure(); } var server = new grpc.Server(options); server.addProtoService(testProto.TestService.service, { emptyCall: handleEmpty, unaryCall: handleUnary, streamingOutputCall: handleStreamingOutput, streamingInputCall: handleStreamingInput, fullDuplexCall: handleFullDuplex, halfDuplexCall: handleHalfDuplex }); var port_num = server.bind('0.0.0.0:' + port, server_creds); return {server: server, port: port_num}; } if (require.main === module) { var parseArgs = require('minimist'); var argv = parseArgs(process.argv, { string: ['port', 'use_tls'] }); var server_obj = getServer(argv.port, argv.use_tls === 'true'); console.log('Server attaching to port ' + argv.port); server_obj.server.start(); } /** * See docs for getServer */ exports.getServer = getServer; grpc-0.11.1/src/node/.gitignore0000644000175000017500000000002312600663151016416 0ustar apollockapollockbuild node_modules grpc-0.11.1/src/node/cli/0000755000175000017500000000000012600663151015202 5ustar apollockapollockgrpc-0.11.1/src/node/cli/service_packager/0000755000175000017500000000000012600663151020477 5ustar apollockapollockgrpc-0.11.1/src/node/cli/service_packager/package.json.template0000644000175000017500000000055012600663151024577 0ustar apollockapollock{ "name": "{{{name}}}", "version": "{{{version}}}", "author": "Google Inc.", "description": "Client library for {{{name}}} built on gRPC", "license": "Apache-2.0", "dependencies": { "grpc": "{{{grpc_version}}}", "google-auth-library": "^0.9.2" }, "main": "index.js", "files": [ "LICENSE", "index.js", "service.json" ] } grpc-0.11.1/src/node/cli/service_packager/index.js0000644000175000017500000000325612600663151022152 0ustar apollockapollock/* * * 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 grpc = require('grpc'); exports.client = grpc.load(__dirname + '/service.json', 'json'); exports.auth = require('google-auth-library'); grpc-0.11.1/src/node/cli/service_packager.js0000644000175000017500000001154112600663151021037 0ustar apollockapollock/* * * 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. * */ 'use strict'; var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var async = require('async'); var pbjs = require('protobufjs/cli/pbjs'); var parseArgs = require('minimist'); var Mustache = require('mustache'); var package_json = require('../package.json'); var template_path = path.resolve(__dirname, 'service_packager'); var package_tpl_path = path.join(template_path, 'package.json.template'); var arg_format = { string: ['include', 'out', 'name', 'version'], alias: { include: 'i', out: 'o', name: 'n', version: 'v' } }; // TODO(mlumish): autogenerate README.md from proto file /** * Render package.json file from template using provided parameters. * @param {Object} params Map of parameter names to values * @param {function(Error, string)} callback Callback to pass rendered template * text to */ function generatePackage(params, callback) { fs.readFile(package_tpl_path, {encoding: 'utf-8'}, function(err, template) { if (err) { callback(err); } else { var rendered = Mustache.render(template, params); callback(null, rendered); } }); } /** * Copy a file * @param {string} src_path The filepath to copy from * @param {string} dest_path The filepath to copy to */ function copyFile(src_path, dest_path) { fs.createReadStream(src_path).pipe(fs.createWriteStream(dest_path)); } /** * Run the script. Copies the index.js and LICENSE files to the output path, * renders the package.json template to the output path, and generates a * service.json file from the input proto files using pbjs. The arguments are * taken directly from the command line, and handled as follows: * -i (--include) : An include path for pbjs (can be dpulicated) * -o (--output): The output path * -n (--name): The name of the package * -v (--version): The package version * @param {Array} argv The argument vector */ function main(argv) { var args = parseArgs(argv, arg_format); var out_path = path.resolve(args.out); var include_dirs = []; if (args.include) { include_dirs = _.map(_.flatten([args.include]), function(p) { return path.resolve(p); }); } args.grpc_version = package_json.version; generatePackage(args, function(err, rendered) { if (err) throw err; fs.writeFile(path.join(out_path, 'package.json'), rendered, function(err) { if (err) throw err; }); }); copyFile(path.join(template_path, 'index.js'), path.join(out_path, 'index.js')); copyFile(path.join(__dirname, '..', 'LICENSE'), path.join(out_path, 'LICENSE')); var service_stream = fs.createWriteStream(path.join(out_path, 'service.json')); var pbjs_args = _.flatten(['node', 'pbjs', args._[0], '-legacy', _.map(include_dirs, function(dir) { return "-path=" + dir; })]); var old_stdout = process.stdout; process.__defineGetter__('stdout', function() { return service_stream; }); var pbjs_status = pbjs.main(pbjs_args); process.__defineGetter__('stdout', function() { return old_stdout; }); if (pbjs_status !== pbjs.STATUS_OK) { throw new Error('pbjs failed with status code ' + pbjs_status); } } exports.main = main; grpc-0.11.1/src/node/jsdoc_conf.json0000644000175000017500000000062712600663151017442 0ustar apollockapollock{ "tags": { "allowUnknownTags": true }, "source": { "include": [ "index.js", "src" ], "includePattern": ".+\\.js(doc)?$", "excludePattern": "(^|\\/|\\\\)_" }, "opts": { "package": "package.json", "readme": "README.md" }, "plugins": [], "templates": { "cleverLinks": false, "monospaceLinks": false, "default": { "outputSourceFiles": true } } } grpc-0.11.1/src/node/index.js0000644000175000017500000001174412600663151016107 0ustar apollockapollock/* * * 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. * */ 'use strict'; var _ = require('lodash'); var ProtoBuf = require('protobufjs'); var client = require('./src/client.js'); var server = require('./src/server.js'); var Metadata = require('./src/metadata.js'); var grpc = require('bindings')('grpc'); /** * Load a gRPC object from an existing ProtoBuf.Reflect object. * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. * @return {Object} The resulting gRPC object */ exports.loadObject = function loadObject(value) { var result = {}; if (value.className === 'Namespace') { _.each(value.children, function(child) { result[child.name] = loadObject(child); }); return result; } else if (value.className === 'Service') { return client.makeProtobufClientConstructor(value); } else if (value.className === 'Message' || value.className === 'Enum') { return value.build(); } else { return value; } }; var loadObject = exports.loadObject; /** * Load a gRPC object from a .proto file. * @param {string} filename The file to load * @param {string=} format The file format to expect. Must be either 'proto' or * 'json'. Defaults to 'proto' * @return {Object} The resulting gRPC object */ exports.load = function load(filename, format) { if (!format) { format = 'proto'; } var builder; switch(format) { case 'proto': builder = ProtoBuf.loadProtoFile(filename); break; case 'json': builder = ProtoBuf.loadJsonFile(filename); break; default: throw new Error('Unrecognized format "' + format + '"'); } return loadObject(builder.ns); }; /** * Get a function that a client can use to update metadata with authentication * information from a Google Auth credential object, which comes from the * google-auth-library. * @param {Object} credential The credential object to use * @return {function(Object, callback)} Metadata updater function */ exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) { /** * Update a metadata object with authentication information. * @param {string} authURI The uri to authenticate to * @param {Object} metadata Metadata object * @param {function(Error, Object)} callback */ return function updateMetadata(authURI, metadata, callback) { credential.getRequestMetadata(authURI, function(err, header) { if (err) { callback(err); return; } metadata.add('authorization', header.Authorization); callback(null, metadata); }); }; }; /** * @see module:src/server.Server */ exports.Server = server.Server; /** * @see module:src/metadata */ exports.Metadata = Metadata; /** * Status name to code number mapping */ exports.status = grpc.status; /** * Propagate flag name to number mapping */ exports.propagate = grpc.propagate; /** * Call error name to code number mapping */ exports.callError = grpc.callError; /** * Write flag name to code number mapping */ exports.writeFlags = grpc.writeFlags; /** * Credentials factories */ exports.Credentials = grpc.Credentials; /** * ServerCredentials factories */ exports.ServerCredentials = grpc.ServerCredentials; /** * @see module:src/client.makeClientConstructor */ exports.makeGenericClientConstructor = client.makeClientConstructor; /** * @see module:src/client.getClientChannel */ exports.getClientChannel = client.getClientChannel; /** * @see module:src/client.waitForClientReady */ exports.waitForClientReady = client.waitForClientReady; grpc-0.11.1/src/csharp/0000755000175000017500000000000012600663151014766 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core.Tests/0000755000175000017500000000000012600663151017651 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core.Tests/TestResult.xml0000644000175000017500000000600512600663151022512 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs0000644000175000017500000000757212600663151023777 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class ChannelOptionsTest { [Test] public void IntOption() { var option = new ChannelOption("somename", 1); Assert.AreEqual(ChannelOption.OptionType.Integer, option.Type); Assert.AreEqual("somename", option.Name); Assert.AreEqual(1, option.IntValue); Assert.Throws(typeof(InvalidOperationException), () => { var s = option.StringValue; }); } [Test] public void StringOption() { var option = new ChannelOption("somename", "ABCDEF"); Assert.AreEqual(ChannelOption.OptionType.String, option.Type); Assert.AreEqual("somename", option.Name); Assert.AreEqual("ABCDEF", option.StringValue); Assert.Throws(typeof(InvalidOperationException), () => { var s = option.IntValue; }); } [Test] public void ConstructorPreconditions() { Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, "abc"); }); Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, 1); }); Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption("abc", null); }); } [Test] public void CreateChannelArgsNull() { var channelArgs = ChannelOptions.CreateChannelArgs(null); Assert.IsTrue(channelArgs.IsInvalid); } [Test] public void CreateChannelArgsEmpty() { var options = new List(); var channelArgs = ChannelOptions.CreateChannelArgs(options); channelArgs.Dispose(); } [Test] public void CreateChannelArgs() { var options = new List { new ChannelOption("ABC", "XYZ"), new ChannelOption("somename", "IJKLM"), new ChannelOption("intoption", 12345), new ChannelOption("GHIJK", 12345), }; var channelArgs = ChannelOptions.CreateChannelArgs(options); channelArgs.Dispose(); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs0000644000175000017500000000610412600663151024161 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; using Grpc.Core; using NUnit.Framework; namespace Grpc.Core.Tests { public class GrpcEnvironmentTest { [Test] public void InitializeAndShutdownGrpcEnvironment() { var env = GrpcEnvironment.AddRef(); Assert.IsNotNull(env.CompletionQueue); GrpcEnvironment.Release(); } [Test] public void SubsequentInvocations() { var env1 = GrpcEnvironment.AddRef(); var env2 = GrpcEnvironment.AddRef(); Assert.AreSame(env1, env2); GrpcEnvironment.Release(); GrpcEnvironment.Release(); } [Test] public void InitializeAfterShutdown() { Assert.AreEqual(0, GrpcEnvironment.GetRefCount()); var env1 = GrpcEnvironment.AddRef(); GrpcEnvironment.Release(); var env2 = GrpcEnvironment.AddRef(); GrpcEnvironment.Release(); Assert.AreNotSame(env1, env2); } [Test] public void ReleaseWithoutAddRef() { Assert.AreEqual(0, GrpcEnvironment.GetRefCount()); Assert.Throws(typeof(InvalidOperationException), () => GrpcEnvironment.Release()); } [Test] public void GetCoreVersionString() { var coreVersion = GrpcEnvironment.GetCoreVersionString(); var parts = coreVersion.Split('.'); Assert.AreEqual(4, parts.Length); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/PInvokeTest.cs0000644000175000017500000001030212600663151022407 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class PInvokeTest { int counter; [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_test_nop(IntPtr ptr); /// /// (~1.26us .NET Windows) /// [Test] public void CompletionQueueCreateDestroyBenchmark() { BenchmarkUtil.RunBenchmark( 100000, 1000000, () => { CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create(); cq.Dispose(); }); } /// /// Approximate results: /// (~80ns Mono Linux) /// (~110ns .NET Windows) /// [Test] public void NativeCallbackBenchmark() { OpCompletionDelegate handler = Handler; counter = 0; BenchmarkUtil.RunBenchmark( 1000000, 10000000, () => { grpcsharp_test_callback(handler); }); Assert.AreNotEqual(0, counter); } /// /// Creating a new native-to-managed callback has significant overhead /// compared to using an existing one. We need to be aware of this. /// (~50us on Mono Linux!!!) /// (~1.1us on .NET Windows) /// [Test] public void NewNativeCallbackBenchmark() { counter = 0; BenchmarkUtil.RunBenchmark( 10000, 10000, () => { grpcsharp_test_callback(new OpCompletionDelegate(Handler)); }); Assert.AreNotEqual(0, counter); } /// /// Tests overhead of a simple PInvoke call. /// (~46ns .NET Windows) /// [Test] public void NopPInvokeBenchmark() { BenchmarkUtil.RunBenchmark( 1000000, 100000000, () => { grpcsharp_test_nop(IntPtr.Zero); }); } private void Handler(bool success) { counter++; } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs0000644000175000017500000001400212600663151024665 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class ContextPropagationTest { MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { helper = new MockServiceHelper(); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public async Task PropagateCancellation() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { // check that we didn't obtain the default cancellation token. Assert.IsTrue(context.CancellationToken.CanBeCanceled); return "PASS"; }); helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { var propagationToken = context.CreatePropagationToken(); Assert.IsNotNull(propagationToken.ParentCall); var callOptions = new CallOptions(propagationToken: propagationToken); return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); }); var cts = new CancellationTokenSource(); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token))); await call.RequestStream.CompleteAsync(); Assert.AreEqual("PASS", await call); } [Test] public async Task PropagateDeadline() { var deadline = DateTime.UtcNow.AddDays(7); helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { Assert.IsTrue(context.Deadline < deadline.AddMinutes(1)); Assert.IsTrue(context.Deadline > deadline.AddMinutes(-1)); return "PASS"; }); helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { Assert.Throws(typeof(ArgumentException), () => { // Trying to override deadline while propagating deadline from parent call will throw. Calls.BlockingUnaryCall(helper.CreateUnaryCall( new CallOptions(deadline: DateTime.UtcNow.AddDays(8), propagationToken: context.CreatePropagationToken())), ""); }); var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken()); return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(deadline: deadline))); await call.RequestStream.CompleteAsync(); Assert.AreEqual("PASS", await call); } [Test] public async Task SuppressDeadlinePropagation() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { Assert.AreEqual(DateTime.MaxValue, context.Deadline); return "PASS"; }); helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { Assert.IsTrue(context.CancellationToken.CanBeCanceled); var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken(new ContextPropagationOptions(propagateDeadline: false))); return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); }); var cts = new CancellationTokenSource(); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(deadline: DateTime.UtcNow.AddDays(7)))); await call.RequestStream.CompleteAsync(); Assert.AreEqual("PASS", await call); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/ShutdownTest.cs0000644000175000017500000000532612600663151022661 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class ShutdownTest { const string Host = "127.0.0.1"; MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { helper = new MockServiceHelper(Host); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); } [Test] public async Task AbandonedCall() { helper.DuplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => { await requestStream.ToListAsync(); }); var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall(new CallOptions(deadline: DateTime.UtcNow.AddMilliseconds(1)))); channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/CompressionTest.cs0000644000175000017500000001066312600663151023347 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class CompressionTest { MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { helper = new MockServiceHelper(); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void WriteOptions_Unary() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); return request; }); var callOptions = new CallOptions(writeOptions: new WriteOptions(WriteFlags.NoCompress)); Calls.BlockingUnaryCall(helper.CreateUnaryCall(callOptions), "abc"); } [Test] public async Task WriteOptions_DuplexStreaming() { helper.DuplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => { await requestStream.ToListAsync(); context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); await context.WriteResponseHeadersAsync(new Metadata { { "ascii-header", "abcdefg" } }); await responseStream.WriteAsync("X"); responseStream.WriteOptions = null; await responseStream.WriteAsync("Y"); responseStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); await responseStream.WriteAsync("Z"); }); var callOptions = new CallOptions(writeOptions: new WriteOptions(WriteFlags.NoCompress)); var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall(callOptions)); // check that write options from call options are propagated to request stream. Assert.IsTrue((call.RequestStream.WriteOptions.Flags & WriteFlags.NoCompress) != 0); call.RequestStream.WriteOptions = new WriteOptions(); await call.RequestStream.WriteAsync("A"); call.RequestStream.WriteOptions = null; await call.RequestStream.WriteAsync("B"); call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); await call.RequestStream.WriteAsync("C"); await call.RequestStream.CompleteAsync(); await call.ResponseStream.ToListAsync(); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs0000644000175000017500000001542412600663151024504 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class MarshallingErrorsTest { const string Host = "127.0.0.1"; MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { var marshaller = new Marshaller( (str) => { if (str == "UNSERIALIZABLE_VALUE") { // Google.Protobuf throws exception inherited from IOException throw new IOException("Error serializing the message."); } return System.Text.Encoding.UTF8.GetBytes(str); }, (payload) => { var s = System.Text.Encoding.UTF8.GetString(payload); if (s == "UNPARSEABLE_VALUE") { // Google.Protobuf throws exception inherited from IOException throw new IOException("Error parsing the message."); } return s; }); helper = new MockServiceHelper(Host, marshaller); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void ResponseParsingError_UnaryResponse() { helper.UnaryHandler = new UnaryServerMethod((request, context) => { return Task.FromResult("UNPARSEABLE_VALUE"); }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "REQUEST")); Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); } [Test] public void ResponseParsingError_StreamingResponse() { helper.ServerStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => { await responseStream.WriteAsync("UNPARSEABLE_VALUE"); await Task.Delay(10000); }); var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "REQUEST"); var ex = Assert.Throws(async () => await call.ResponseStream.MoveNext()); Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); } [Test] public void RequestParsingError_UnaryRequest() { helper.UnaryHandler = new UnaryServerMethod((request, context) => { return Task.FromResult("RESPONSE"); }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNPARSEABLE_VALUE")); // Spec doesn't define the behavior. With the current implementation server handler throws exception which results in StatusCode.Unknown. Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); } [Test] public async Task RequestParsingError_StreamingRequest() { helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { Assert.Throws(async () => await requestStream.MoveNext()); return "RESPONSE"; }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); await call.RequestStream.WriteAsync("UNPARSEABLE_VALUE"); Assert.AreEqual("RESPONSE", await call); } [Test] public void RequestSerializationError_BlockingUnary() { Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); } [Test] public void RequestSerializationError_AsyncUnary() { Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); } [Test] public async Task RequestSerializationError_ClientStreaming() { helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync()); return "RESPONSE"; }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); await call.RequestStream.WriteAsync("A"); Assert.Throws(async () => await call.RequestStream.WriteAsync("UNSERIALIZABLE_VALUE")); await call.RequestStream.WriteAsync("B"); await call.RequestStream.CompleteAsync(); Assert.AreEqual("RESPONSE", await call); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs0000644000175000017500000002102612600663151023553 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { /// /// Allows setting up a mock service in the client-server tests easily. /// public class MockServiceHelper { public const string ServiceName = "tests.Test"; readonly string host; readonly ServerServiceDefinition serviceDefinition; readonly Method unaryMethod; readonly Method clientStreamingMethod; readonly Method serverStreamingMethod; readonly Method duplexStreamingMethod; UnaryServerMethod unaryHandler; ClientStreamingServerMethod clientStreamingHandler; ServerStreamingServerMethod serverStreamingHandler; DuplexStreamingServerMethod duplexStreamingHandler; Server server; Channel channel; public MockServiceHelper(string host = null, Marshaller marshaller = null) { this.host = host ?? "localhost"; marshaller = marshaller ?? Marshallers.StringMarshaller; unaryMethod = new Method( MethodType.Unary, ServiceName, "Unary", marshaller, marshaller); clientStreamingMethod = new Method( MethodType.ClientStreaming, ServiceName, "ClientStreaming", marshaller, marshaller); serverStreamingMethod = new Method( MethodType.ServerStreaming, ServiceName, "ServerStreaming", marshaller, marshaller); duplexStreamingMethod = new Method( MethodType.DuplexStreaming, ServiceName, "DuplexStreaming", marshaller, marshaller); serviceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName) .AddMethod(unaryMethod, (request, context) => unaryHandler(request, context)) .AddMethod(clientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context)) .AddMethod(serverStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context)) .AddMethod(duplexStreamingMethod, (requestStream, responseStream, context) => duplexStreamingHandler(requestStream, responseStream, context)) .Build(); var defaultStatus = new Status(StatusCode.Unknown, "Default mock implementation. Please provide your own."); unaryHandler = new UnaryServerMethod(async (request, context) => { context.Status = defaultStatus; return ""; }); clientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { context.Status = defaultStatus; return ""; }); serverStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => { context.Status = defaultStatus; }); duplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => { context.Status = defaultStatus; }); } /// /// Returns the default server for this service and creates one if not yet created. /// public Server GetServer() { if (server == null) { server = new Server { Services = { serviceDefinition }, Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } }; } return server; } /// /// Returns the default channel for this service and creates one if not yet created. /// public Channel GetChannel() { if (channel == null) { channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure); } return channel; } public CallInvocationDetails CreateUnaryCall(CallOptions options = default(CallOptions)) { return new CallInvocationDetails(channel, unaryMethod, options); } public CallInvocationDetails CreateClientStreamingCall(CallOptions options = default(CallOptions)) { return new CallInvocationDetails(channel, clientStreamingMethod, options); } public CallInvocationDetails CreateServerStreamingCall(CallOptions options = default(CallOptions)) { return new CallInvocationDetails(channel, serverStreamingMethod, options); } public CallInvocationDetails CreateDuplexStreamingCall(CallOptions options = default(CallOptions)) { return new CallInvocationDetails(channel, duplexStreamingMethod, options); } public string Host { get { return this.host; } } public ServerServiceDefinition ServiceDefinition { get { return this.serviceDefinition; } } public UnaryServerMethod UnaryHandler { get { return this.unaryHandler; } set { unaryHandler = value; } } public ClientStreamingServerMethod ClientStreamingHandler { get { return this.clientStreamingHandler; } set { clientStreamingHandler = value; } } public ServerStreamingServerMethod ServerStreamingHandler { get { return this.serverStreamingHandler; } set { serverStreamingHandler = value; } } public DuplexStreamingServerMethod DuplexStreamingHandler { get { return this.duplexStreamingHandler; } set { duplexStreamingHandler = value; } } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/0000755000175000017500000000000012600663151021425 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs0000644000175000017500000001760612600663151024377 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using Grpc.Core.Internal; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class TimespecTest { [Test] public void Now_IsInUtc() { Assert.AreEqual(DateTimeKind.Utc, Timespec.Now.ToDateTime().Kind); } [Test] public void Now_AgreesWithUtcNow() { var timespec = Timespec.Now; var utcNow = DateTime.UtcNow; TimeSpan difference = utcNow - timespec.ToDateTime(); // This test is inherently a race - but the two timestamps // should really be way less that a minute apart. Assert.IsTrue(difference.TotalSeconds < 60); } [Test] public void InfFuture() { var timespec = Timespec.InfFuture; } [Test] public void InfPast() { var timespec = Timespec.InfPast; } [Test] public void TimespecSizeIsNativeSize() { Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec))); } [Test] public void ToDateTime() { Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), new Timespec(IntPtr.Zero, 0).ToDateTime()); Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50), new Timespec(new IntPtr(10), 5000).ToDateTime()); Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc), new Timespec(new IntPtr(1437452508), 0).ToDateTime()); // before epoch Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10), new Timespec(new IntPtr(-5), 1000).ToDateTime()); // infinity Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime()); Assert.AreEqual(DateTime.MinValue, Timespec.InfPast.ToDateTime()); // nanos are rounded to ticks are rounded up Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1), new Timespec(IntPtr.Zero, 99).ToDateTime()); // Illegal inputs Assert.Throws(typeof(InvalidOperationException), () => new Timespec(new IntPtr(0), -2).ToDateTime()); Assert.Throws(typeof(InvalidOperationException), () => new Timespec(new IntPtr(0), 1000 * 1000 * 1000).ToDateTime()); Assert.Throws(typeof(InvalidOperationException), () => new Timespec(new IntPtr(0), 0, GPRClockType.Monotonic).ToDateTime()); } [Test] public void ToDateTime_ReturnsUtc() { Assert.AreEqual(DateTimeKind.Utc, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind); Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind); } [Test] public void ToDateTime_Overflow() { // we can only get overflow in ticks arithmetic on 64-bit if (IntPtr.Size == 8) { var timespec = new Timespec(new IntPtr(long.MaxValue - 100), 0); Assert.AreNotEqual(Timespec.InfFuture, timespec); Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime()); Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(long.MinValue + 100), 0).ToDateTime()); } else { Console.WriteLine("Test cannot be run on this platform, skipping the test."); } } [Test] public void ToDateTime_OutOfDateTimeRange() { // we can only get out of range on 64-bit, on 32 bit the max // timestamp is ~ Jan 19 2038, which is far within range of DateTime // same case for min value. if (IntPtr.Size == 8) { // DateTime range goes up to year 9999, 20000 years from now should // be out of range. long seconds = 20000L * 365L * 24L * 3600L; var timespec = new Timespec(new IntPtr(seconds), 0); Assert.AreNotEqual(Timespec.InfFuture, timespec); Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime()); Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(-seconds), 0).ToDateTime()); } else { Console.WriteLine("Test cannot be run on this platform, skipping the test"); } } [Test] public void FromDateTime() { Assert.AreEqual(new Timespec(IntPtr.Zero, 0), Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))); Assert.AreEqual(new Timespec(new IntPtr(10), 5000), Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50))); Assert.AreEqual(new Timespec(new IntPtr(1437452508), 0), Timespec.FromDateTime(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc))); // before epoch Assert.AreEqual(new Timespec(new IntPtr(-5), 1000), Timespec.FromDateTime(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10))); // infinity Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(DateTime.MaxValue)); Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(DateTime.MinValue)); // illegal inputs Assert.Throws(typeof(ArgumentException), () => Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified))); } [Test] public void FromDateTime_OutOfTimespecRange() { // we can only get overflow in Timespec on 32-bit if (IntPtr.Size == 4) { Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc))); Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc))); } else { Console.WriteLine("Test cannot be run on this platform, skipping the test."); } } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/ChannelArgsSafeHandleTest.cs0000644000175000017500000000521212600663151026714 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class ChannelArgsSafeHandleTest { [Test] public void CreateEmptyAndDestroy() { var channelArgs = ChannelArgsSafeHandle.Create(0); channelArgs.Dispose(); } [Test] public void CreateNonEmptyAndDestroy() { var channelArgs = ChannelArgsSafeHandle.Create(5); channelArgs.Dispose(); } [Test] public void CreateNullAndDestroy() { var channelArgs = ChannelArgsSafeHandle.CreateNull(); channelArgs.Dispose(); } [Test] public void CreateFillAndDestroy() { var channelArgs = ChannelArgsSafeHandle.Create(3); channelArgs.SetInteger(0, "somekey", 12345); channelArgs.SetString(1, "somekey", "abcdefghijkl"); channelArgs.SetString(2, "somekey", "XYZ"); channelArgs.Dispose(); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs0000644000175000017500000000577012600663151027257 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class MetadataArraySafeHandleTest { [Test] public void CreateEmptyAndDestroy() { var nativeMetadata = MetadataArraySafeHandle.Create(new Metadata()); nativeMetadata.Dispose(); } [Test] public void CreateAndDestroy() { var metadata = new Metadata { { "host", "somehost" }, { "header2", "header value" }, }; var nativeMetadata = MetadataArraySafeHandle.Create(metadata); nativeMetadata.Dispose(); } [Test] public void ReadMetadataFromPtrUnsafe() { var metadata = new Metadata { { "host", "somehost" }, { "header2", "header value" } }; var nativeMetadata = MetadataArraySafeHandle.Create(metadata); var copy = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(nativeMetadata.Handle); Assert.AreEqual(2, copy.Count); Assert.AreEqual("host", copy[0].Key); Assert.AreEqual("somehost", copy[0].Value); Assert.AreEqual("header2", copy[1].Key); Assert.AreEqual("header value", copy[1].Value); nativeMetadata.Dispose(); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueEventTest.cs0000644000175000017500000000400612600663151026734 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class CompletionQueueEventTest { [Test] public void CreateAndDestroy() { Assert.AreEqual(CompletionQueueEvent.NativeSize, Marshal.SizeOf(typeof(CompletionQueueEvent))); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs0000644000175000017500000001700412600663151024467 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class AsyncCallTest { Channel channel; FakeNativeCall fakeCall; AsyncCall asyncCall; [SetUp] public void Init() { channel = new Channel("localhost", Credentials.Insecure); fakeCall = new FakeNativeCall(); var callDetails = new CallInvocationDetails(channel, "someMethod", null, Marshallers.StringMarshaller, Marshallers.StringMarshaller, new CallOptions()); asyncCall = new AsyncCall(callDetails, fakeCall); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); } [Test] public void AsyncUnary_CompletionSuccess() { var resultTask = asyncCall.UnaryCallAsync("abc"); fakeCall.UnaryResponseClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()), new byte[] { 1, 2, 3 }, new Metadata()); Assert.IsTrue(resultTask.IsCompleted); Assert.IsTrue(fakeCall.IsDisposed); Assert.AreEqual(Status.DefaultSuccess, asyncCall.GetStatus()); } [Test] public void AsyncUnary_CompletionFailure() { var resultTask = asyncCall.UnaryCallAsync("abc"); fakeCall.UnaryResponseClientHandler(false, new ClientSideStatus(new Status(StatusCode.Internal, ""), null), new byte[] { 1, 2, 3 }, new Metadata()); Assert.IsTrue(resultTask.IsCompleted); Assert.IsTrue(fakeCall.IsDisposed); Assert.AreEqual(StatusCode.Internal, asyncCall.GetStatus().StatusCode); Assert.IsNull(asyncCall.GetTrailers()); var ex = Assert.Throws(() => resultTask.GetAwaiter().GetResult()); Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); } internal class FakeNativeCall : INativeCall { public UnaryResponseClientHandler UnaryResponseClientHandler { get; set; } public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler { get; set; } public ReceivedMessageHandler ReceivedMessageHandler { get; set; } public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler { get; set; } public SendCompletionHandler SendCompletionHandler { get; set; } public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler { get; set; } public bool IsCancelled { get; set; } public bool IsDisposed { get; set; } public void Cancel() { IsCancelled = true; } public void CancelWithStatus(Status status) { IsCancelled = true; } public string GetPeer() { return "PEER"; } public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { UnaryResponseClientHandler = callback; } public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { throw new NotImplementedException(); } public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray) { UnaryResponseClientHandler = callback; } public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { ReceivedStatusOnClientHandler = callback; } public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray) { ReceivedStatusOnClientHandler = callback; } public void StartReceiveMessage(ReceivedMessageHandler callback) { ReceivedMessageHandler = callback; } public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback) { ReceivedResponseHeadersHandler = callback; } public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray) { SendCompletionHandler = callback; } public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata) { SendCompletionHandler = callback; } public void StartSendCloseFromClient(SendCompletionHandler callback) { SendCompletionHandler = callback; } public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata) { SendCompletionHandler = callback; } public void StartServerSide(ReceivedCloseOnServerHandler callback) { ReceivedCloseOnServerHandler = callback; } public void Dispose() { IsDisposed = true; } } } }grpc-0.11.1/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs0000644000175000017500000000452412600663151027652 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests { public class CompletionQueueSafeHandleTest { [Test] public void CreateAndDestroy() { var cq = CompletionQueueSafeHandle.Create(); cq.Dispose(); } [Test] public void CreateAndShutdown() { var cq = CompletionQueueSafeHandle.Create(); cq.Shutdown(); var ev = cq.Next(); cq.Dispose(); Assert.AreEqual(GRPCCompletionType.Shutdown, ev.type); Assert.AreNotEqual(IntPtr.Zero, ev.success); Assert.AreEqual(IntPtr.Zero, ev.tag); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/MetadataTest.cs0000644000175000017500000001236712600663151022571 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class MetadataTest { [Test] public void AsciiEntry() { var entry = new Metadata.Entry("ABC", "XYZ"); Assert.IsFalse(entry.IsBinary); Assert.AreEqual("abc", entry.Key); // key is in lowercase. Assert.AreEqual("XYZ", entry.Value); CollectionAssert.AreEqual(new[] { (byte)'X', (byte)'Y', (byte)'Z' }, entry.ValueBytes); Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc-bin", "xyz")); Assert.AreEqual("[Entry: key=abc, value=XYZ]", entry.ToString()); } [Test] public void BinaryEntry() { var bytes = new byte[] { 1, 2, 3 }; var entry = new Metadata.Entry("ABC-BIN", bytes); Assert.IsTrue(entry.IsBinary); Assert.AreEqual("abc-bin", entry.Key); // key is in lowercase. Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; }); CollectionAssert.AreEqual(bytes, entry.ValueBytes); Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc", bytes)); Assert.AreEqual("[Entry: key=abc-bin, valueBytes=System.Byte[]]", entry.ToString()); } [Test] public void AsciiEntry_KeyValidity() { new Metadata.Entry("ABC", "XYZ"); new Metadata.Entry("0123456789abc", "XYZ"); new Metadata.Entry("-abc", "XYZ"); new Metadata.Entry("a_bc_", "XYZ"); Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz")); Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz")); } [Test] public void Entry_ConstructionPreconditions() { Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry(null, "xyz")); Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry("abc", (string)null)); Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry("abc-bin", (byte[])null)); } [Test] public void Entry_Immutable() { var origBytes = new byte[] { 1, 2, 3 }; var bytes = new byte[] { 1, 2, 3 }; var entry = new Metadata.Entry("ABC-BIN", bytes); bytes[0] = 255; // changing the array passed to constructor should have any effect. CollectionAssert.AreEqual(origBytes, entry.ValueBytes); entry.ValueBytes[0] = 255; CollectionAssert.AreEqual(origBytes, entry.ValueBytes); } [Test] public void Entry_CreateUnsafe_Ascii() { var bytes = new byte[] { (byte)'X', (byte)'y' }; var entry = Metadata.Entry.CreateUnsafe("abc", bytes); Assert.IsFalse(entry.IsBinary); Assert.AreEqual("abc", entry.Key); Assert.AreEqual("Xy", entry.Value); CollectionAssert.AreEqual(bytes, entry.ValueBytes); } [Test] public void Entry_CreateUnsafe_Binary() { var bytes = new byte[] { 1, 2, 3 }; var entry = Metadata.Entry.CreateUnsafe("abc-bin", bytes); Assert.IsTrue(entry.IsBinary); Assert.AreEqual("abc-bin", entry.Key); Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; }); CollectionAssert.AreEqual(bytes, entry.ValueBytes); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs0000644000175000017500000001431212600663151022652 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { /// /// Tests for Deadline support. /// public class TimeoutsTest { MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { helper = new MockServiceHelper(); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void InfiniteDeadline() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { Assert.AreEqual(DateTime.MaxValue, context.Deadline); return "PASS"; }); // no deadline specified, check server sees infinite deadline Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); // DateTime.MaxValue deadline specified, check server sees infinite deadline Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MaxValue)), "abc")); } [Test] public void DeadlineTransferredToServer() { var clientDeadline = DateTime.UtcNow + TimeSpan.FromDays(7); helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { // A fairly relaxed check that the deadline set by client and deadline seen by server // are in agreement. C core takes care of the work with transferring deadline over the wire, // so we don't need an exact check here. Assert.IsTrue(Math.Abs((clientDeadline - context.Deadline).TotalMilliseconds) < 5000); return "PASS"; }); Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: clientDeadline)), "abc"); } [Test] public void DeadlineInThePast() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { await Task.Delay(60000); return "FAIL"; }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MinValue)), "abc")); // We can't guarantee the status code always DeadlineExceeded. See issue #2685. Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } [Test] public void DeadlineExceededStatusOnTimeout() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { await Task.Delay(60000); return "FAIL"; }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc")); // We can't guarantee the status code always DeadlineExceeded. See issue #2685. Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } [Test] public async Task ServerReceivesCancellationOnTimeout() { var serverReceivedCancellationTcs = new TaskCompletionSource(); helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { // wait until cancellation token is fired. var tcs = new TaskCompletionSource(); context.CancellationToken.Register(() => { tcs.SetResult(null); }); await tcs.Task; serverReceivedCancellationTcs.SetResult(true); return ""; }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc")); // We can't guarantee the status code always DeadlineExceeded. See issue #2685. Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); Assert.IsTrue(await serverReceivedCancellationTcs.Task); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/ClientServerTest.cs0000644000175000017500000002515112600663151023451 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class ClientServerTest { const string Host = "127.0.0.1"; MockServiceHelper helper; Server server; Channel channel; [SetUp] public void Init() { helper = new MockServiceHelper(Host); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public async Task UnaryCall() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { return request; }); Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC")); Assert.AreEqual("ABC", await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "ABC")); } [Test] public void UnaryCall_ServerHandlerThrows() { helper.UnaryHandler = new UnaryServerMethod((request, context) => { throw new Exception("This was thrown on purpose by a test"); }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); var ex2 = Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unknown, ex2.Status.StatusCode); } [Test] public void UnaryCall_ServerHandlerThrowsRpcException() { helper.UnaryHandler = new UnaryServerMethod((request, context) => { throw new RpcException(new Status(StatusCode.Unauthenticated, "")); }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); var ex2 = Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); } [Test] public void UnaryCall_ServerHandlerSetsStatus() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { context.Status = new Status(StatusCode.Unauthenticated, ""); return ""; }); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); var ex2 = Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc")); Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); } [Test] public async Task ClientStreamingCall() { helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { string result = ""; await requestStream.ForEachAsync(async (request) => { result += request; }); await Task.Delay(100); return result; }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" }); Assert.AreEqual("ABC", await call.ResponseAsync); } [Test] public async Task ClientStreamingCall_CancelAfterBegin() { var barrier = new TaskCompletionSource(); helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { barrier.SetResult(null); await requestStream.ToListAsync(); return ""; }); var cts = new CancellationTokenSource(); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token))); await barrier.Task; // make sure the handler has started. cts.Cancel(); var ex = Assert.Throws(async () => await call.ResponseAsync); Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); } [Test] public async Task AsyncUnaryCall_EchoMetadata() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { foreach (Metadata.Entry metadataEntry in context.RequestHeaders) { if (metadataEntry.Key != "user-agent") { context.ResponseTrailers.Add(metadataEntry); } } return ""; }); var headers = new Metadata { { "ascii-header", "abcdefg" }, { "binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff } } }; var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptions(headers: headers)), "ABC"); await call; Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); var trailers = call.GetTrailers(); Assert.AreEqual(2, trailers.Count); Assert.AreEqual(headers[0].Key, trailers[0].Key); Assert.AreEqual(headers[0].Value, trailers[0].Value); Assert.AreEqual(headers[1].Key, trailers[1].Key); CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes); } [Test] public void UnaryCallPerformance() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { return request; }); var callDetails = helper.CreateUnaryCall(); BenchmarkUtil.RunBenchmark(100, 100, () => { Calls.BlockingUnaryCall(callDetails, "ABC"); }); } [Test] public void UnknownMethodHandler() { var nonexistentMethod = new Method( MethodType.Unary, MockServiceHelper.ServiceName, "NonExistentMethod", Marshallers.StringMarshaller, Marshallers.StringMarshaller); var callDetails = new CallInvocationDetails(channel, nonexistentMethod, new CallOptions()); var ex = Assert.Throws(() => Calls.BlockingUnaryCall(callDetails, "abc")); Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode); } [Test] public void UserAgentStringPresent() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value; }); string userAgent = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"); Assert.IsTrue(userAgent.StartsWith("grpc-csharp/")); } [Test] public void PeerInfoPresent() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { return context.Peer; }); string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"); Assert.IsTrue(peer.Contains(Host)); } [Test] public async Task Channel_WaitForStateChangedAsync() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { return request; }); Assert.Throws(typeof(TaskCanceledException), async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(10))); var stateChangedTask = channel.WaitForStateChangedAsync(channel.State); await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"); await stateChangedTask; Assert.AreEqual(ChannelState.Ready, channel.State); } [Test] public async Task Channel_ConnectAsync() { await channel.ConnectAsync(); Assert.AreEqual(ChannelState.Ready, channel.State); await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(1000)); Assert.AreEqual(ChannelState.Ready, channel.State); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs0000644000175000017500000001701312600663151024134 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { /// /// Tests for response headers support. /// public class ResponseHeadersTest { MockServiceHelper helper; Server server; Channel channel; Metadata headers; [SetUp] public void Init() { helper = new MockServiceHelper(); server = helper.GetServer(); server.Start(); channel = helper.GetChannel(); headers = new Metadata { { "ascii-header", "abcdefg" } }; } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public async Task ResponseHeadersAsync_UnaryCall() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { await context.WriteResponseHeadersAsync(headers); return "PASS"; }); var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(), ""); var responseHeaders = await call.ResponseHeadersAsync; Assert.AreEqual(headers.Count, responseHeaders.Count); Assert.AreEqual("ascii-header", responseHeaders[0].Key); Assert.AreEqual("abcdefg", responseHeaders[0].Value); Assert.AreEqual("PASS", await call.ResponseAsync); } [Test] public async Task ResponseHeadersAsync_ClientStreamingCall() { helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { await context.WriteResponseHeadersAsync(headers); return "PASS"; }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); await call.RequestStream.CompleteAsync(); var responseHeaders = await call.ResponseHeadersAsync; Assert.AreEqual("ascii-header", responseHeaders[0].Key); Assert.AreEqual("PASS", await call.ResponseAsync); } [Test] public async Task ResponseHeadersAsync_ServerStreamingCall() { helper.ServerStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => { await context.WriteResponseHeadersAsync(headers); await responseStream.WriteAsync("PASS"); }); var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); var responseHeaders = await call.ResponseHeadersAsync; Assert.AreEqual("ascii-header", responseHeaders[0].Key); CollectionAssert.AreEqual(new[] { "PASS" }, await call.ResponseStream.ToListAsync()); } [Test] public async Task ResponseHeadersAsync_DuplexStreamingCall() { helper.DuplexStreamingHandler = new DuplexStreamingServerMethod(async (requestStream, responseStream, context) => { await context.WriteResponseHeadersAsync(headers); while (await requestStream.MoveNext()) { await responseStream.WriteAsync(requestStream.Current); } }); var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall()); var responseHeaders = await call.ResponseHeadersAsync; var messages = new[] { "PASS" }; await call.RequestStream.WriteAllAsync(messages); Assert.AreEqual("ascii-header", responseHeaders[0].Key); CollectionAssert.AreEqual(messages, await call.ResponseStream.ToListAsync()); } [Test] public void WriteResponseHeaders_NullNotAllowed() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { Assert.Throws(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null)); return "PASS"; }); Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "")); } [Test] public void WriteResponseHeaders_AllowedOnlyOnce() { helper.UnaryHandler = new UnaryServerMethod(async (request, context) => { await context.WriteResponseHeadersAsync(headers); try { await context.WriteResponseHeadersAsync(headers); Assert.Fail(); } catch (InvalidOperationException expected) { } return "PASS"; }); Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "")); } [Test] public async Task WriteResponseHeaders_NotAllowedAfterWrite() { helper.ServerStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => { await responseStream.WriteAsync("A"); try { await context.WriteResponseHeadersAsync(headers); Assert.Fail(); } catch (InvalidOperationException expected) { } await responseStream.WriteAsync("B"); }); var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); var responses = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new[] { "A", "B" }, responses); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/packages.config0000644000175000017500000000042112600663151022613 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Core.Tests/Properties/0000755000175000017500000000000012600663151022005 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs0000644000175000017500000000057512600663151024736 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Core.Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.Core.Tests/.gitignore0000644000175000017500000000002412600663151021635 0ustar apollockapollocktest-results bin objgrpc-0.11.1/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj0000644000175000017500000001063112600663151023757 0ustar apollockapollock Debug AnyCPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB} Library Grpc.Core.Tests Grpc.Core.Tests v4.5 true full false bin\Debug DEBUG; prompt 4 pdbonly true bin\Release prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll False ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll False ..\packages\NUnit.2.6.4\lib\nunit.framework.dll ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll False ..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll False ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core Designer grpc-0.11.1/src/csharp/Grpc.Core.Tests/ChannelTest.cs0000644000175000017500000000613112600663151022411 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class ChannelTest { [Test] public void Constructor_RejectsInvalidParams() { Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure)); } [Test] public void State_IdleAfterCreation() { var channel = new Channel("localhost", Credentials.Insecure); Assert.AreEqual(ChannelState.Idle, channel.State); channel.ShutdownAsync().Wait(); } [Test] public void WaitForStateChangedAsync_InvalidArgument() { var channel = new Channel("localhost", Credentials.Insecure); Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure)); channel.ShutdownAsync().Wait(); } [Test] public void ResolvedTarget() { var channel = new Channel("127.0.0.1", Credentials.Insecure); Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1")); channel.ShutdownAsync().Wait(); } [Test] public void Shutdown_AllowedOnlyOnce() { var channel = new Channel("localhost", Credentials.Insecure); channel.ShutdownAsync().Wait(); Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult()); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs0000644000175000017500000000524112600663151023445 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { /// /// Tests if the version of nunit-console used is sufficient to run async tests. /// public class NUnitVersionTest { private int testRunCount = 0; [TestFixtureTearDown] public void Cleanup() { if (testRunCount != 2) { Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " + "This test has failed to indicate that."); Console.Error.Flush(); Environment.Exit(1); } } [Test] public void NUnitVersionTest1() { testRunCount++; } // Old version of NUnit will skip this test [Test] public async Task NUnitVersionTest2() { testRunCount++; await Task.Delay(10); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs0000644000175000017500000000525412600663151023057 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class ClientBaseTest { [Test] public void GetAuthUriBase_Valid() { Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com")); Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com/")); Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com:443/")); Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com:443/")); } [Test] public void GetAuthUriBase_Invalid() { Assert.IsNull(ClientBase.GetAuthUriBase("some.googleapi.com:")); Assert.IsNull(ClientBase.GetAuthUriBase("https://some.googleapi.com/")); Assert.IsNull(ClientBase.GetAuthUriBase("dns://some.googleapi.com:443")); // just two slashes Assert.IsNull(ClientBase.GetAuthUriBase("")); } } } grpc-0.11.1/src/csharp/Grpc.Core.Tests/ServerTest.cs0000644000175000017500000000621412600663151022311 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Linq; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Tests { public class ServerTest { [Test] public void StartAndShutdownServer() { Server server = new Server { Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) } }; server.Start(); server.ShutdownAsync().Wait(); } [Test] public void PickUnusedPort() { Server server = new Server { Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) } }; var boundPort = server.Ports.Single(); Assert.AreEqual(0, boundPort.Port); Assert.Greater(boundPort.BoundPort, 0); server.Start(); server.ShutdownAsync().Wait(); } [Test] public void CannotModifyAfterStarted() { Server server = new Server { Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) } }; server.Start(); Assert.Throws(typeof(InvalidOperationException), () => server.Ports.Add("localhost", 9999, ServerCredentials.Insecure)); Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder("serviceName").Build())); server.ShutdownAsync().Wait(); } } } grpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/0000755000175000017500000000000012600663151021124 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs0000644000175000017500000001151512600663151025666 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Grpc.Core; using Grpc.Health.V1Alpha; using NUnit.Framework; namespace Grpc.HealthCheck.Tests { /// /// Tests for HealthCheckServiceImpl /// public class HealthServiceImplTest { [Test] public void SetStatus() { var impl = new HealthServiceImpl(); impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "", "")); impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.NOT_SERVING); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, "", "")); impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", "")); impl.SetStatus("virtual-host", "grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "virtual-host", "grpc.test.TestService")); } [Test] public void ClearStatus() { var impl = new HealthServiceImpl(); impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN); impl.ClearStatus("", ""); Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, "", "")); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", "")); } [Test] public void ClearAll() { var impl = new HealthServiceImpl(); impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN); impl.ClearAll(); Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "", "")); Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "virtual-host", "")); } [Test] public void NullsRejected() { var impl = new HealthServiceImpl(); Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING)); Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING)); Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null, "")); Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus("", null)); } private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service) { return impl.Check(new HealthCheckRequest { Host = host, Service = service }, null).Result.Status; } } } grpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs0000644000175000017500000000705512600663151026055 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Grpc.Core; using Grpc.Health.V1Alpha; using NUnit.Framework; namespace Grpc.HealthCheck.Tests { /// /// Health client talks to health server. /// public class HealthClientServerTest { const string Host = "localhost"; Server server; Channel channel; Grpc.Health.V1Alpha.Health.IHealthClient client; Grpc.HealthCheck.HealthServiceImpl serviceImpl; [TestFixtureSetUp] public void Init() { serviceImpl = new HealthServiceImpl(); server = new Server { Services = { Grpc.Health.V1Alpha.Health.BindService(serviceImpl) }, Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } }; server.Start(); channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); client = Grpc.Health.V1Alpha.Health.NewClient(channel); } [TestFixtureTearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void ServiceIsRunning() { serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); var response = client.Check(new HealthCheckRequest { Host = "", Service = "" }); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status); } [Test] public void ServiceDoesntExist() { Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(new HealthCheckRequest { Host = "", Service = "nonexistent.service" })); } // TODO(jtattermusch): add test with timeout once timeouts are supported } }grpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/packages.config0000644000175000017500000000032312600663151024067 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/Properties/0000755000175000017500000000000012600663151023260 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs0000644000175000017500000000060712600663151026205 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.HealthCheck.Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/.gitignore0000644000175000017500000000001012600663151023103 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj0000644000175000017500000000745612600663151026520 0ustar apollockapollock Debug AnyCPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D} Library Properties Grpc.HealthCheck.Tests Grpc.HealthCheck.Tests v4.5 512 true full false bin\Debug\ prompt 4 pdbonly true bin\Release\ prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk False ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll ..\packages\NUnit.2.6.4\lib\nunit.framework.dll Version.cs {ccc4440e-49f7-4790-b0af-feabb0837ae7} Grpc.Core {aa5e328a-8835-49d7-98ed-c29f2b3049f0} Grpc.HealthCheck grpc-0.11.1/src/csharp/README.md0000644000175000017500000001663612600663151016261 0ustar apollockapollockgRPC C# ======= A C# implementation of gRPC. Status ------ Alpha : Ready for early adopters. Usage: Windows -------------- - Prerequisites: .NET Framework 4.5+, Visual Studio 2013 with NuGet extension installed (VS2015 should work). - Open Visual Studio and start a new project/solution. - Add NuGet package `Grpc` as a dependency (Project options -> Manage NuGet Packages). That will also pull all the transitive dependencies (including the native libraries that gRPC C# is internally using). - Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp. Usage: Linux (Mono) -------------- - Prerequisites: Mono 3.2.8+, MonoDevelop 5.9 with NuGet add-in installed. - Install Linuxbrew and gRPC C Core using instructions in https://github.com/grpc/homebrew-grpc - gRPC C# depends on native shared library libgrpc_csharp_ext.so (Unix flavor of grpc_csharp_ext.dll). This library will be installed to `~/.linuxbrew/lib` by the previous step. To make it visible to mono, you need to: - (preferred approach) add `libgrpc_csharp_ext.so` to `/etc/ld.so.cache` by running: ```sh $ echo "$HOME/.linuxbrew/lib" | sudo tee /etc/ld.so.conf.d/zzz_brew_lib.conf $ sudo ldconfig ``` - (adhoc approach) set `LD_LIBRARY_PATH` environment variable to point to directory containing `libgrpc_csharp_ext.so`: ```sh $ export LD_LIBRARY_PATH=$HOME/.linuxbrew/lib:${LD_LIBRARY_PATH} ``` - (if you are contributor) installing gRPC from sources using `sudo make install_grpc_csharp_ext` also works. - Open MonoDevelop and start a new project/solution. - Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages). - Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp. Usage: MacOS (Mono) -------------- - WARNING: As of now gRPC C# only works on 64bit version of Mono (because we don't compile the native extension for C# in 32bit mode yet). That means your development experience with Xamarin Studio on MacOS will not be great, as you won't be able to run your code directly from Xamarin Studio (which requires 32bit version of Mono). - Prerequisites: Xamarin Studio with NuGet add-in installed. - Install Homebrew and gRPC C Core using instructions in https://github.com/grpc/homebrew-grpc - Install 64-bit version of mono with command `brew install mono` (assumes you've already installed Homebrew). - Open Xamarin Studio and start a new project/solution. - Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages). - *You will be able to build your project in Xamarin Studio, but to run or test it, you will need to run it under 64-bit version of Mono.* - Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp. Building: Windows ----------------- You only need to go through these steps if you are planning to develop gRPC C#. If you are a user of gRPC C#, go to Usage section above. - Prerequisites for development: NET Framework 4.5+, Visual Studio 2013 (with NuGet and NUnit extensions installed). - The grpc_csharp_ext native library needs to be built so you can build the Grpc C# solution. You can either build the native solution in `vsprojects/grpc.sln` from Visual Studio manually, or you can use a convenience batch script that builds everything for you. ``` > buildall.bat ``` - Open Grpc.sln using Visual Studio 2013. NuGet dependencies will be restored upon build (you need to have NuGet add-in installed). Building: Linux (Mono) ---------------------- You only need to go through these steps if you are planning to develop gRPC C#. If you are a user of gRPC C#, go to Usage section above. - Prerequisites for development: Mono 3.2.8+, MonoDevelop 5.9 with NuGet and NUnit add-ins installed. ```sh $ sudo apt-get install mono-devel $ sudo apt-get install nunit nunit-console ``` You can use older versions of MonoDevelop, but then you might need to restore NuGet dependencies manually (by `nuget restore`), because older versions of MonoDevelop don't support NuGet add-in. - Compile and install the gRPC C# extension library (that will be used via P/Invoke from C#). ```sh $ make grpc_csharp_ext $ sudo make install_grpc_csharp_ext ``` - Use MonoDevelop to open the solution Grpc.sln - Build the solution & run all the tests from test view. Tests ----- gRPC C# is using NUnit as the testing framework. Under Visual Studio, make sure NUnit test adapter is installed (under "Extensions and Updates"). Then you should be able to run all the tests using Test Explorer. Under Monodevelop, make sure you installed "NUnit support" in Add-in manager. Then you should be able to run all the test from the Test View. After building the solution, you can also run the tests from command line using nunit-console tool. ```sh # from Grpc.Core.Test/bin/Debug directory $ nunit-console Grpc.Core.Tests.dll ``` Contents -------- - ext: The extension library that wraps C API to be more digestible by C#. - Grpc.Auth: gRPC OAuth2 support. - Grpc.Core: The main gRPC C# library. - Grpc.Examples: API examples for math.proto - Grpc.Examples.MathClient: An example client that sends some requests to math server. - Grpc.Examples.MathServer: An example client that sends some requests to math server. - Grpc.IntegrationTesting: Cross-language gRPC implementation testing (interop testing). Troubleshooting --------------- ### Problem: Unable to load DLL 'grpc_csharp_ext.dll' Internally, gRPC C# uses a native library written in C (gRPC C core) and invokes its functionality via P/Invoke. `grpc_csharp_ext` library is a native extension library that facilitates this by wrapping some C core API into a form that's more digestible for P/Invoke. If you get the above error, it means that the native dependencies could not be located by the C# runtime (or they are incompatible with the current runtime, so they could not be loaded). The solution to this is environment specific. - If you are developing on Windows in Visual Studio, the `grpc_csharp_ext.dll` that is shipped by gRPC nuget packages should be automatically copied to your build destination folder once you build. By adjusting project properties in your VS project file, you can influence which exact configuration of `grpc_csharp_ext.dll` will be used (based on VS version, bitness, debug/release configuration). - If you are running your application that is using gRPC on Windows machine that doesn't have Visual Studio installed, you might need to install [Visual C++ 2013 redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=40784) that contains some system .dll libraries that `grpc_csharp_ext.dll` depends on (see #905 for more details). - On Linux (or Docker), you need to first install gRPC C core and `libgrpc_csharp_ext.so` shared libraries. Currently, the libraries can be installed by `make install_grpc_csharp_ext` or using Linuxbrew (a Debian package is coming soon). Installation on a machine where your application is going to be deployed is no different. - On Mac, you need to first install gRPC C core and `libgrpc_csharp_ext.dylib` shared libraries using Homebrew. See above for installation instruction. Installation on a machine where your application is going to be deployed is no different. - Possible cause for the problem is that the `grpc_csharp_ext` library is installed, but it has different bitness (32/64bit) than your C# runtime (in case you are using mono) or C# application. grpc-0.11.1/src/csharp/buildall.bat0000644000175000017500000000112712600663151017247 0ustar apollockapollock@rem Convenience script to build gRPC C# from command line setlocal @rem enter this directory cd /d %~dp0 @rem Set VS variables (uses Visual Studio 2013) @call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86 @rem Build the C# native extension msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:PlatformToolset=v120 || goto :error msbuild Grpc.sln /p:Configuration=Debug || goto :error msbuild Grpc.sln /p:Configuration=Release || goto :error if "%1" == "BUILD_SIGNED" ( msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error ) endlocal goto :EOF :error echo Failed! exit /b %errorlevel% grpc-0.11.1/src/csharp/Grpc.Examples.Tests/0000755000175000017500000000000012600663151020537 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs0000644000175000017500000001537512600663151025343 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; using NUnit.Framework; namespace Math.Tests { /// /// Math client talks to local math server. /// public class MathClientServerTest { const string Host = "localhost"; Server server; Channel channel; Math.MathClient client; [TestFixtureSetUp] public void Init() { server = new Server { Services = { Math.BindService(new MathServiceImpl()) }, Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } }; server.Start(); channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); client = Math.NewClient(channel); } [TestFixtureTearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void Div1() { DivReply response = client.Div(new DivArgs { Dividend = 10, Divisor = 3 }); Assert.AreEqual(3, response.Quotient); Assert.AreEqual(1, response.Remainder); } [Test] public void Div2() { DivReply response = client.Div(new DivArgs { Dividend = 0, Divisor = 1 }); Assert.AreEqual(0, response.Quotient); Assert.AreEqual(0, response.Remainder); } [Test] public void DivByZero() { var ex = Assert.Throws(() => client.Div(new DivArgs { Dividend = 0, Divisor = 0 })); Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); } [Test] public async Task DivAsync() { DivReply response = await client.DivAsync(new DivArgs { Dividend = 10, Divisor = 3 }); Assert.AreEqual(3, response.Quotient); Assert.AreEqual(1, response.Remainder); } [Test] public async Task Fib() { using (var call = client.Fib(new FibArgs { Limit = 6 })) { var responses = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new List { 1, 1, 2, 3, 5, 8 }, responses.ConvertAll((n) => n.Num_)); } } [Test] public async Task FibWithCancel() { var cts = new CancellationTokenSource(); using (var call = client.Fib(new FibArgs { Limit = 0 }, cancellationToken: cts.Token)) { List responses = new List(); try { while (await call.ResponseStream.MoveNext()) { if (responses.Count == 0) { cts.CancelAfter(500); // make sure we cancel soon } responses.Add(call.ResponseStream.Current.Num_); } Assert.Fail(); } catch (RpcException e) { Assert.IsTrue(responses.Count > 0); Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); } } } [Test] public async Task FibWithDeadline() { using (var call = client.Fib(new FibArgs { Limit = 0 }, deadline: DateTime.UtcNow.AddMilliseconds(500))) { var ex = Assert.Throws(async () => await call.ResponseStream.ToListAsync()); // We can't guarantee the status code always DeadlineExceeded. See issue #2685. Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); } } // TODO: test Fib with limit=0 and cancellation [Test] public async Task Sum() { using (var call = client.Sum()) { var numbers = new List { 10, 20, 30 }.ConvertAll(n => new Num { Num_ = n }); await call.RequestStream.WriteAllAsync(numbers); var result = await call.ResponseAsync; Assert.AreEqual(60, result.Num_); } } [Test] public async Task DivMany() { var divArgsList = new List { new DivArgs { Dividend = 10, Divisor = 3 }, new DivArgs { Dividend = 100, Divisor = 21 }, new DivArgs { Dividend = 7, Divisor = 2 } }; using (var call = client.DivMany()) { await call.RequestStream.WriteAllAsync(divArgsList); var result = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder)); } } } } grpc-0.11.1/src/csharp/Grpc.Examples.Tests/packages.config0000644000175000017500000000043412600663151023505 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj0000644000175000017500000000655212600663151025542 0ustar apollockapollock Debug AnyCPU 10.0.0 2.0 {143B1C29-C442-4BE0-BF3F-A8F92288AC9F} Library Grpc.Examples.Tests Grpc.Examples.Tests v4.5 true full false bin\Debug DEBUG; prompt 4 pdbonly true bin\Release prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk False ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll ..\packages\NUnit.2.6.4\lib\nunit.framework.dll False ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core {7DC1433E-3225-42C7-B7EA-546D56E27A4B} Grpc.Examples grpc-0.11.1/src/csharp/Grpc.Examples.Tests/Properties/0000755000175000017500000000000012600663151022673 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs0000644000175000017500000000060112600663151025612 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Examples.Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.Examples.Tests/.gitignore0000644000175000017500000000002512600663151022524 0ustar apollockapollocktest-results bin obj grpc-0.11.1/src/csharp/ext/0000755000175000017500000000000012600663151015566 5ustar apollockapollockgrpc-0.11.1/src/csharp/ext/grpc_csharp_ext.c0000644000175000017500000007736712600663151021131 0ustar apollockapollock/* * * 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/support/string.h" #include #include #include #include #include #include #include #include #include #include #ifdef GPR_WIN32 #define GPR_EXPORT __declspec(dllexport) #define GPR_CALLTYPE __stdcall #endif #ifndef GPR_EXPORT #define GPR_EXPORT #endif #ifndef GPR_CALLTYPE #define GPR_CALLTYPE #endif grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) { gpr_slice slice = gpr_slice_from_copied_buffer(buffer, len); grpc_byte_buffer *bb = grpc_raw_byte_buffer_create(&slice, 1); gpr_slice_unref(slice); return bb; } /* * Helper to maintain lifetime of batch op inputs and store batch op outputs. */ typedef struct gprcsharp_batch_context { grpc_metadata_array send_initial_metadata; grpc_byte_buffer *send_message; struct { grpc_metadata_array trailing_metadata; char *status_details; } send_status_from_server; grpc_metadata_array recv_initial_metadata; grpc_byte_buffer *recv_message; struct { grpc_metadata_array trailing_metadata; grpc_status_code status; char *status_details; size_t status_details_capacity; } recv_status_on_client; int recv_close_on_server_cancelled; struct { grpc_call *call; grpc_call_details call_details; grpc_metadata_array request_metadata; } server_rpc_new; } grpcsharp_batch_context; GPR_EXPORT grpcsharp_batch_context *GPR_CALLTYPE grpcsharp_batch_context_create() { grpcsharp_batch_context *ctx = gpr_malloc(sizeof(grpcsharp_batch_context)); memset(ctx, 0, sizeof(grpcsharp_batch_context)); return ctx; } /* * Destroys array->metadata. * The array pointer itself is not freed. */ void grpcsharp_metadata_array_destroy_metadata_only( grpc_metadata_array *array) { gpr_free(array->metadata); } /* * Destroys keys, values and array->metadata. * The array pointer itself is not freed. */ void grpcsharp_metadata_array_destroy_metadata_including_entries( grpc_metadata_array *array) { size_t i; if (array->metadata) { for (i = 0; i < array->count; i++) { gpr_free((void *)array->metadata[i].key); gpr_free((void *)array->metadata[i].value); } } gpr_free(array->metadata); } /* * Fully destroys the metadata array. */ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_array_destroy_full(grpc_metadata_array *array) { if (!array) { return; } grpcsharp_metadata_array_destroy_metadata_including_entries(array); gpr_free(array); } /* * Creates an empty metadata array with given capacity. * Array can later be destroyed by grpc_metadata_array_destroy_full. */ GPR_EXPORT grpc_metadata_array *GPR_CALLTYPE grpcsharp_metadata_array_create(size_t capacity) { grpc_metadata_array *array = (grpc_metadata_array *)gpr_malloc(sizeof(grpc_metadata_array)); grpc_metadata_array_init(array); array->capacity = capacity; array->count = 0; if (capacity > 0) { array->metadata = (grpc_metadata *)gpr_malloc(sizeof(grpc_metadata) * capacity); memset(array->metadata, 0, sizeof(grpc_metadata) * capacity); } else { array->metadata = NULL; } return array; } GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_array_add(grpc_metadata_array *array, const char *key, const char *value, size_t value_length) { size_t i = array->count; GPR_ASSERT(array->count < array->capacity); array->metadata[i].key = gpr_strdup(key); array->metadata[i].value = (char *)gpr_malloc(value_length); memcpy((void *)array->metadata[i].value, value, value_length); array->metadata[i].value_length = value_length; array->count++; } GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_metadata_array_count(grpc_metadata_array *array) { return (gpr_intptr)array->count; } GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_metadata_array_get_key(grpc_metadata_array *array, size_t index) { GPR_ASSERT(index < array->count); return array->metadata[index].key; } GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_metadata_array_get_value(grpc_metadata_array *array, size_t index) { GPR_ASSERT(index < array->count); return array->metadata[index].value; } GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_metadata_array_get_value_length( grpc_metadata_array *array, size_t index) { GPR_ASSERT(index < array->count); return (gpr_intptr)array->metadata[index].value_length; } /* Move contents of metadata array */ void grpcsharp_metadata_array_move(grpc_metadata_array *dest, grpc_metadata_array *src) { if (!src) { dest->capacity = 0; dest->count = 0; dest->metadata = NULL; return; } dest->capacity = src->capacity; dest->count = src->count; dest->metadata = src->metadata; src->capacity = 0; src->count = 0; src->metadata = NULL; } GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_destroy(grpcsharp_batch_context *ctx) { if (!ctx) { return; } grpcsharp_metadata_array_destroy_metadata_including_entries( &(ctx->send_initial_metadata)); grpc_byte_buffer_destroy(ctx->send_message); grpcsharp_metadata_array_destroy_metadata_including_entries( &(ctx->send_status_from_server.trailing_metadata)); gpr_free(ctx->send_status_from_server.status_details); grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata)); grpc_byte_buffer_destroy(ctx->recv_message); grpcsharp_metadata_array_destroy_metadata_only( &(ctx->recv_status_on_client.trailing_metadata)); gpr_free((void *)ctx->recv_status_on_client.status_details); /* NOTE: ctx->server_rpc_new.call is not destroyed because callback handler is supposed to take its ownership. */ grpc_call_details_destroy(&(ctx->server_rpc_new.call_details)); grpcsharp_metadata_array_destroy_metadata_only( &(ctx->server_rpc_new.request_metadata)); gpr_free(ctx); } GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE grpcsharp_batch_context_recv_initial_metadata( const grpcsharp_batch_context *ctx) { return &(ctx->recv_initial_metadata); } GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_batch_context_recv_message_length( const grpcsharp_batch_context *ctx) { if (!ctx->recv_message) { return -1; } return grpc_byte_buffer_length(ctx->recv_message); } /* * Copies data from recv_message to a buffer. Fatal error occurs if * buffer is too small. */ GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer( const grpcsharp_batch_context *ctx, char *buffer, size_t buffer_len) { grpc_byte_buffer_reader reader; gpr_slice slice; size_t offset = 0; grpc_byte_buffer_reader_init(&reader, ctx->recv_message); while (grpc_byte_buffer_reader_next(&reader, &slice)) { size_t len = GPR_SLICE_LENGTH(slice); GPR_ASSERT(offset + len <= buffer_len); memcpy(buffer + offset, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)); offset += len; gpr_slice_unref(slice); } } GPR_EXPORT grpc_status_code GPR_CALLTYPE grpcsharp_batch_context_recv_status_on_client_status( const grpcsharp_batch_context *ctx) { return ctx->recv_status_on_client.status; } GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_batch_context_recv_status_on_client_details( const grpcsharp_batch_context *ctx) { return ctx->recv_status_on_client.status_details; } GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE grpcsharp_batch_context_recv_status_on_client_trailing_metadata( const grpcsharp_batch_context *ctx) { return &(ctx->recv_status_on_client.trailing_metadata); } GPR_EXPORT grpc_call *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_call( const grpcsharp_batch_context *ctx) { return ctx->server_rpc_new.call; } GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_method( const grpcsharp_batch_context *ctx) { return ctx->server_rpc_new.call_details.method; } GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_host( const grpcsharp_batch_context *ctx) { return ctx->server_rpc_new.call_details.host; } GPR_EXPORT gpr_timespec GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_deadline( const grpcsharp_batch_context *ctx) { return ctx->server_rpc_new.call_details.deadline; } GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_request_metadata( const grpcsharp_batch_context *ctx) { return &(ctx->server_rpc_new.request_metadata); } GPR_EXPORT gpr_int32 GPR_CALLTYPE grpcsharp_batch_context_recv_close_on_server_cancelled( const grpcsharp_batch_context *ctx) { return (gpr_int32) ctx->recv_close_on_server_cancelled; } /* Init & shutdown */ GPR_EXPORT void GPR_CALLTYPE grpcsharp_init(void) { grpc_init(); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_shutdown(void) { grpc_shutdown(); } /* Completion queue */ GPR_EXPORT grpc_completion_queue *GPR_CALLTYPE grpcsharp_completion_queue_create(void) { return grpc_completion_queue_create(NULL); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_completion_queue_shutdown(grpc_completion_queue *cq) { grpc_completion_queue_shutdown(cq); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_completion_queue_destroy(grpc_completion_queue *cq) { grpc_completion_queue_destroy(cq); } GPR_EXPORT grpc_event GPR_CALLTYPE grpcsharp_completion_queue_next(grpc_completion_queue *cq) { return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } GPR_EXPORT grpc_event GPR_CALLTYPE grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) { return grpc_completion_queue_pluck(cq, tag, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } /* Channel */ GPR_EXPORT grpc_channel *GPR_CALLTYPE grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) { return grpc_insecure_channel_create(target, args, NULL); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) { grpc_channel_destroy(channel); } GPR_EXPORT grpc_call *GPR_CALLTYPE grpcsharp_channel_create_call(grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *cq, const char *method, const char *host, gpr_timespec deadline) { return grpc_channel_create_call(channel, parent_call, propagation_mask, cq, method, host, deadline, NULL); } GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE grpcsharp_channel_check_connectivity_state(grpc_channel *channel, gpr_int32 try_to_connect) { return grpc_channel_check_connectivity_state(channel, try_to_connect); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_watch_connectivity_state( grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, grpcsharp_batch_context *ctx) { grpc_channel_watch_connectivity_state(channel, last_observed_state, deadline, cq, ctx); } GPR_EXPORT char *GPR_CALLTYPE grpcsharp_channel_get_target(grpc_channel *channel) { return grpc_channel_get_target(channel); } /* Channel args */ GPR_EXPORT grpc_channel_args *GPR_CALLTYPE grpcsharp_channel_args_create(size_t num_args) { grpc_channel_args *args = (grpc_channel_args *)gpr_malloc(sizeof(grpc_channel_args)); memset(args, 0, sizeof(grpc_channel_args)); args->num_args = num_args; args->args = (grpc_arg *)gpr_malloc(sizeof(grpc_arg) * num_args); memset(args->args, 0, sizeof(grpc_arg) * num_args); return args; } GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_set_string(grpc_channel_args *args, size_t index, const char *key, const char *value) { GPR_ASSERT(args); GPR_ASSERT(index < args->num_args); args->args[index].type = GRPC_ARG_STRING; args->args[index].key = gpr_strdup(key); args->args[index].value.string = gpr_strdup(value); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_set_integer(grpc_channel_args *args, size_t index, const char *key, int value) { GPR_ASSERT(args); GPR_ASSERT(index < args->num_args); args->args[index].type = GRPC_ARG_INTEGER; args->args[index].key = gpr_strdup(key); args->args[index].value.integer = value; } GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_destroy(grpc_channel_args *args) { size_t i; if (args) { for (i = 0; i < args->num_args; i++) { gpr_free(args->args[i].key); if (args->args[i].type == GRPC_ARG_STRING) { gpr_free(args->args[i].value.string); } } gpr_free(args->args); gpr_free(args); } } /* Timespec */ GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(gpr_clock_type clock_type) { return gpr_now(clock_type); } GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(gpr_clock_type clock_type) { return gpr_inf_future(clock_type); } GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_past(gpr_clock_type clock_type) { return gpr_inf_past(clock_type); } GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock) { return gpr_convert_clock_type(t, target_clock); } GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) { return sizeof(gpr_timespec); } /* Call */ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel(grpc_call *call) { return grpc_call_cancel(call, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status, const char *description) { return grpc_call_cancel_with_status(call, status, description, NULL); } GPR_EXPORT char *GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call *call) { return grpc_call_get_peer(call); } GPR_EXPORT void GPR_CALLTYPE gprsharp_free(void *p) { gpr_free(p); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) { grpc_call_destroy(call); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, size_t send_buffer_len, grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[6]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; grpcsharp_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata); ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[1].data.send_message = ctx->send_message; ops[1].flags = write_flags; ops[1].reserved = NULL; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ops[2].flags = 0; ops[2].reserved = NULL; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[3].flags = 0; ops[3].reserved = NULL; ops[4].op = GRPC_OP_RECV_MESSAGE; ops[4].data.recv_message = &(ctx->recv_message); ops[4].flags = 0; ops[4].reserved = NULL; ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[5].data.recv_status_on_client.trailing_metadata = &(ctx->recv_status_on_client.trailing_metadata); ops[5].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); /* not using preallocation for status_details */ ops[5].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); ops[5].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[5].flags = 0; ops[5].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(grpc_call *call, grpcsharp_batch_context *ctx, grpc_metadata_array *initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[4]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; grpcsharp_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata); ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; ops[0].reserved = NULL; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[1].flags = 0; ops[1].reserved = NULL; ops[2].op = GRPC_OP_RECV_MESSAGE; ops[2].data.recv_message = &(ctx->recv_message); ops[2].flags = 0; ops[2].reserved = NULL; ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[3].data.recv_status_on_client.trailing_metadata = &(ctx->recv_status_on_client.trailing_metadata); ops[3].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); /* not using preallocation for status_details */ ops[3].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); ops[3].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[3].flags = 0; ops[3].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, size_t send_buffer_len, grpc_metadata_array *initial_metadata, gpr_uint32 write_flags) { /* TODO: don't use magic number */ grpc_op ops[4]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; grpcsharp_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata); ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[1].data.send_message = ctx->send_message; ops[1].flags = write_flags; ops[1].reserved = NULL; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ops[2].flags = 0; ops[2].reserved = NULL; ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[3].data.recv_status_on_client.trailing_metadata = &(ctx->recv_status_on_client.trailing_metadata); ops[3].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); /* not using preallocation for status_details */ ops[3].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); ops[3].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[3].flags = 0; ops[3].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(grpc_call *call, grpcsharp_batch_context *ctx, grpc_metadata_array *initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[2]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; grpcsharp_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata); ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; ops[0].reserved = NULL; ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[1].data.recv_status_on_client.trailing_metadata = &(ctx->recv_status_on_client.trailing_metadata); ops[1].data.recv_status_on_client.status = &(ctx->recv_status_on_client.status); /* not using preallocation for status_details */ ops[1].data.recv_status_on_client.status_details = &(ctx->recv_status_on_client.status_details); ops[1].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[1].flags = 0; ops[1].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata( grpc_call *call, grpcsharp_batch_context *ctx) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_RECV_INITIAL_METADATA; ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[0].flags = 0; ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, size_t send_buffer_len, gpr_uint32 write_flags, gpr_int32 send_empty_initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[2]; size_t nops = send_empty_initial_metadata ? 2 : 1; ops[0].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[0].data.send_message = ctx->send_message; ops[0].flags = write_flags; ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; ops[1].data.send_initial_metadata.count = 0; ops[1].data.send_initial_metadata.metadata = NULL; ops[1].flags = 0; ops[1].reserved = NULL; return grpc_call_start_batch(call, ops, nops, ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(grpc_call *call, grpcsharp_batch_context *ctx) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ops[0].flags = 0; ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code, const char *status_details, grpc_metadata_array *trailing_metadata, gpr_int32 send_empty_initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[2]; size_t nops = send_empty_initial_metadata ? 2 : 1; ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER; ops[0].data.send_status_from_server.status = status_code; ops[0].data.send_status_from_server.status_details = gpr_strdup(status_details); grpcsharp_metadata_array_move( &(ctx->send_status_from_server.trailing_metadata), trailing_metadata); ops[0].data.send_status_from_server.trailing_metadata_count = ctx->send_status_from_server.trailing_metadata.count; ops[0].data.send_status_from_server.trailing_metadata = ctx->send_status_from_server.trailing_metadata.metadata; ops[0].flags = 0; ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; ops[1].data.send_initial_metadata.count = 0; ops[1].data.send_initial_metadata.metadata = NULL; ops[1].flags = 0; ops[1].reserved = NULL; return grpc_call_start_batch(call, ops, nops, ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_RECV_MESSAGE; ops[0].data.recv_message = &(ctx->recv_message); ops[0].flags = 0; ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_RECV_CLOSE_ON_SERVER; ops[0].data.recv_close_on_server.cancelled = (&ctx->recv_close_on_server_cancelled); ops[0].flags = 0; ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata(grpc_call *call, grpcsharp_batch_context *ctx, grpc_metadata_array *initial_metadata) { /* TODO: don't use magic number */ grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; grpcsharp_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata); ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count; ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } /* Server */ GPR_EXPORT grpc_server *GPR_CALLTYPE grpcsharp_server_create(grpc_completion_queue *cq, const grpc_channel_args *args) { grpc_server *server = grpc_server_create(args, NULL); grpc_server_register_completion_queue(server, cq, NULL); return server; } GPR_EXPORT gpr_int32 GPR_CALLTYPE grpcsharp_server_add_insecure_http2_port(grpc_server *server, const char *addr) { return grpc_server_add_insecure_http2_port(server, addr); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_start(grpc_server *server) { grpc_server_start(server); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_shutdown_and_notify_callback(grpc_server *server, grpc_completion_queue *cq, grpcsharp_batch_context *ctx) { grpc_server_shutdown_and_notify(server, cq, ctx); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_cancel_all_calls(grpc_server *server) { grpc_server_cancel_all_calls(server); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_destroy(grpc_server *server) { grpc_server_destroy(server); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_server_request_call(grpc_server *server, grpc_completion_queue *cq, grpcsharp_batch_context *ctx) { return grpc_server_request_call( server, &(ctx->server_rpc_new.call), &(ctx->server_rpc_new.call_details), &(ctx->server_rpc_new.request_metadata), cq, cq, ctx); } /* Security */ GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_ssl_credentials_create(const char *pem_root_certs, const char *key_cert_pair_cert_chain, const char *key_cert_pair_private_key) { grpc_ssl_pem_key_cert_pair key_cert_pair; if (key_cert_pair_cert_chain || key_cert_pair_private_key) { key_cert_pair.cert_chain = key_cert_pair_cert_chain; key_cert_pair.private_key = key_cert_pair_private_key; return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL); } else { GPR_ASSERT(!key_cert_pair_cert_chain); GPR_ASSERT(!key_cert_pair_private_key); return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL); } } GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *creds) { grpc_credentials_release(creds); } GPR_EXPORT grpc_channel *GPR_CALLTYPE grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target, const grpc_channel_args *args) { return grpc_secure_channel_create(creds, target, args, NULL); } GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE grpcsharp_ssl_server_credentials_create( const char *pem_root_certs, const char **key_cert_pair_cert_chain_array, const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs, int force_client_auth) { size_t i; grpc_server_credentials *creds; grpc_ssl_pem_key_cert_pair *key_cert_pairs = gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs); memset(key_cert_pairs, 0, sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs); for (i = 0; i < num_key_cert_pairs; i++) { if (key_cert_pair_cert_chain_array[i] || key_cert_pair_private_key_array[i]) { key_cert_pairs[i].cert_chain = key_cert_pair_cert_chain_array[i]; key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i]; } } creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs, num_key_cert_pairs, force_client_auth, NULL); gpr_free(key_cert_pairs); return creds; } GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_credentials_release( grpc_server_credentials *creds) { grpc_server_credentials_release(creds); } GPR_EXPORT gpr_int32 GPR_CALLTYPE grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { return grpc_server_add_secure_http2_port(server, addr, creds); } /* Logging */ typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line, gpr_uint64 thd_id, const char *severity_string, const char *msg); static grpcsharp_log_func log_func = NULL; /* Redirects gpr_log to log_func callback */ static void grpcsharp_log_handler(gpr_log_func_args *args) { log_func(args->file, args->line, gpr_thd_currentid(), gpr_log_severity_string(args->severity), args->message); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_redirect_log(grpcsharp_log_func func) { GPR_ASSERT(func); log_func = func; gpr_set_log_function(grpcsharp_log_handler); } typedef void(GPR_CALLTYPE *test_callback_funcptr)(gpr_int32 success); /* Version info */ GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_version_string() { return grpc_version_string(); } /* For testing */ GPR_EXPORT void GPR_CALLTYPE grpcsharp_test_callback(test_callback_funcptr callback) { callback(1); } /* For testing */ GPR_EXPORT void *GPR_CALLTYPE grpcsharp_test_nop(void *ptr) { return ptr; } /* For testing */ GPR_EXPORT gpr_int32 GPR_CALLTYPE grpcsharp_sizeof_grpc_event(void) { return sizeof(grpc_event); } grpc-0.11.1/src/csharp/Settings.StyleCop0000644000175000017500000004636312600663151020266 0ustar apollockapollock False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False grpc-0.11.1/src/csharp/Grpc.HealthCheck/0000755000175000017500000000000012600663151020023 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj0000644000175000017500000000733012600663151024305 0ustar apollockapollock Debug AnyCPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0} Library Properties Grpc.HealthCheck Grpc.HealthCheck v4.5 512 bin\$(Configuration)\Grpc.HealthCheck.Xml true full false bin\Debug\ prompt 4 pdbonly true bin\Release\ prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk False ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll Version.cs {ccc4440e-49f7-4790-b0af-feabb0837ae7} Grpc.Core grpc-0.11.1/src/csharp/Grpc.HealthCheck/proto/0000755000175000017500000000000012600663151021166 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.HealthCheck/proto/health.proto0000644000175000017500000000374012600663151023524 0ustar apollockapollock// 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. // TODO(jtattermusch): switch to proto3 once C# supports that. syntax = "proto3"; package grpc.health.v1alpha; option csharp_namespace = "Grpc.Health.V1Alpha"; message HealthCheckRequest { string host = 1; string service = 2; } message HealthCheckResponse { enum ServingStatus { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; } ServingStatus status = 1; } service Health { rpc Check(HealthCheckRequest) returns (HealthCheckResponse); }grpc-0.11.1/src/csharp/Grpc.HealthCheck/Settings.StyleCop0000644000175000017500000000043112600663151023305 0ustar apollockapollock Health.cs False grpc-0.11.1/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs0000644000175000017500000001211112600663151023716 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Health.V1Alpha; namespace Grpc.HealthCheck { /// /// Implementation of a simple Health service. Useful for health checking. /// /// Registering service with a server: /// /// var serviceImpl = new HealthServiceImpl(); /// server = new Server(); /// server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl)); /// /// public class HealthServiceImpl : Grpc.Health.V1Alpha.Health.IHealth { private readonly object myLock = new object(); private readonly Dictionary statusMap = new Dictionary(); /// /// Sets the health status for given host and service. /// /// The host. Cannot be null. /// The service. Cannot be null. /// the health status public void SetStatus(string host, string service, HealthCheckResponse.Types.ServingStatus status) { lock (myLock) { statusMap[CreateKey(host, service)] = status; } } /// /// Clears health status for given host and service. /// /// The host. Cannot be null. /// The service. Cannot be null. public void ClearStatus(string host, string service) { lock (myLock) { statusMap.Remove(CreateKey(host, service)); } } /// /// Clears statuses for all hosts and services. /// public void ClearAll() { lock (myLock) { statusMap.Clear(); } } /// /// Performs a health status check. /// /// The check request. /// The call context. /// The asynchronous response. public Task Check(HealthCheckRequest request, ServerCallContext context) { lock (myLock) { var host = request.Host; var service = request.Service; HealthCheckResponse.Types.ServingStatus status; if (!statusMap.TryGetValue(CreateKey(host, service), out status)) { // TODO(jtattermusch): returning specific status from server handler is not supported yet. throw new RpcException(new Status(StatusCode.NotFound, "")); } return Task.FromResult(new HealthCheckResponse { Status = status }); } } private static Key CreateKey(string host, string service) { return new Key(host, service); } private struct Key { public Key(string host, string service) { this.Host = Preconditions.CheckNotNull(host); this.Service = Preconditions.CheckNotNull(service); } readonly string Host; readonly string Service; } } } grpc-0.11.1/src/csharp/Grpc.HealthCheck/packages.config0000644000175000017500000000032612600663151022771 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.HealthCheck/HealthGrpc.cs0000644000175000017500000001075212600663151022400 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: health.proto #region Designer generated code using System; using System.Threading; using System.Threading.Tasks; using Grpc.Core; namespace Grpc.Health.V1Alpha { public static class Health { static readonly string __ServiceName = "grpc.health.v1alpha.Health"; static readonly Marshaller __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckRequest.Parser.ParseFrom); static readonly Marshaller __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckResponse.Parser.ParseFrom); static readonly Method __Method_Check = new Method( MethodType.Unary, __ServiceName, "Check", __Marshaller_HealthCheckRequest, __Marshaller_HealthCheckResponse); // service descriptor public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor { get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.Services[0]; } } // client interface public interface IHealthClient { global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options); AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options); } // server-side interface public interface IHealth { Task Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, ServerCallContext context); } // client stub public class HealthClient : ClientBase, IHealthClient { public HealthClient(Channel channel) : base(channel) { } public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options) { var call = CreateCall(__Method_Check, options); return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } public AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options) { var call = CreateCall(__Method_Check, options); return Calls.AsyncUnaryCall(call, request); } } // creates service definition that can be registered with a server public static ServerServiceDefinition BindService(IHealth serviceImpl) { return ServerServiceDefinition.CreateBuilder(__ServiceName) .AddMethod(__Method_Check, serviceImpl.Check).Build(); } // creates a new client public static HealthClient NewClient(Channel channel) { return new HealthClient(channel); } } } #endregion grpc-0.11.1/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec0000644000175000017500000000230612600663151024300 0ustar apollockapollock Grpc.HealthCheck gRPC C# Healthchecking Implementation of gRPC health service Example implementation of grpc.health.v1alpha service that can be used for health-checking. $version$ Google Inc. grpc-packages https://github.com/grpc/grpc/blob/master/LICENSE https://github.com/grpc/grpc false Copyright 2015, Google Inc. gRPC health check grpc-0.11.1/src/csharp/Grpc.HealthCheck/Health.cs0000644000175000017500000002143612600663151021565 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: health.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code using pb = global::Google.Protobuf; using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Grpc.Health.V1Alpha { namespace Proto { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Health { #region Descriptor public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; static Health() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CgxoZWFsdGgucHJvdG8SE2dycGMuaGVhbHRoLnYxYWxwaGEiMwoSSGVhbHRo", "Q2hlY2tSZXF1ZXN0EgwKBGhvc3QYASABKAkSDwoHc2VydmljZRgCIAEoCSKZ", "AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRJGCgZzdGF0dXMYASABKA4yNi5ncnBj", "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0", "YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5H", "EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", "bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", "dGguVjFBbHBoYWIGcHJvdG8z")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckRequest), new[]{ "Host", "Service" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse), new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) }, null) })); } #endregion } } #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class HealthCheckRequest : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HealthCheckRequest()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.MessageTypes[0]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public HealthCheckRequest() { OnConstruction(); } partial void OnConstruction(); public HealthCheckRequest(HealthCheckRequest other) : this() { host_ = other.host_; service_ = other.service_; } public HealthCheckRequest Clone() { return new HealthCheckRequest(this); } public const int HostFieldNumber = 1; private string host_ = ""; public string Host { get { return host_; } set { host_ = pb::Preconditions.CheckNotNull(value, "value"); } } public const int ServiceFieldNumber = 2; private string service_ = ""; public string Service { get { return service_; } set { service_ = pb::Preconditions.CheckNotNull(value, "value"); } } public override bool Equals(object other) { return Equals(other as HealthCheckRequest); } public bool Equals(HealthCheckRequest other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Host != other.Host) return false; if (Service != other.Service) return false; return true; } public override int GetHashCode() { int hash = 1; if (Host.Length != 0) hash ^= Host.GetHashCode(); if (Service.Length != 0) hash ^= Service.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Host.Length != 0) { output.WriteRawTag(10); output.WriteString(Host); } if (Service.Length != 0) { output.WriteRawTag(18); output.WriteString(Service); } } public int CalculateSize() { int size = 0; if (Host.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Host); } if (Service.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Service); } return size; } public void MergeFrom(HealthCheckRequest other) { if (other == null) { return; } if (other.Host.Length != 0) { Host = other.Host; } if (other.Service.Length != 0) { Service = other.Service; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 10: { Host = input.ReadString(); break; } case 18: { Service = input.ReadString(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class HealthCheckResponse : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HealthCheckResponse()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.MessageTypes[1]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public HealthCheckResponse() { OnConstruction(); } partial void OnConstruction(); public HealthCheckResponse(HealthCheckResponse other) : this() { status_ = other.status_; } public HealthCheckResponse Clone() { return new HealthCheckResponse(this); } public const int StatusFieldNumber = 1; private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN; public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status { get { return status_; } set { status_ = value; } } public override bool Equals(object other) { return Equals(other as HealthCheckResponse); } public bool Equals(HealthCheckResponse other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Status != other.Status) return false; return true; } public override int GetHashCode() { int hash = 1; if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) hash ^= Status.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { output.WriteRawTag(8); output.WriteEnum((int) Status); } } public int CalculateSize() { int size = 0; if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status); } return size; } public void MergeFrom(HealthCheckResponse other) { if (other == null) { return; } if (other.Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { Status = other.Status; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { status_ = (global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) input.ReadEnum(); break; } } } } #region Nested types [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Types { public enum ServingStatus { UNKNOWN = 0, SERVING = 1, NOT_SERVING = 2, } } #endregion } #endregion } #endregion Designer generated code grpc-0.11.1/src/csharp/Grpc.HealthCheck/Properties/0000755000175000017500000000000012600663151022157 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs0000644000175000017500000000060012600663151025075 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.HealthCheck")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")]grpc-0.11.1/src/csharp/Grpc.HealthCheck/.gitignore0000644000175000017500000000001012600663151022002 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/keys/0000755000175000017500000000000012600663151015741 5ustar apollockapollockgrpc-0.11.1/src/csharp/keys/README.md0000644000175000017500000000013412600663151017216 0ustar apollockapollockContents -------- - Grpc.public.snk: Public key to verify strong name of gRPC assemblies.grpc-0.11.1/src/csharp/keys/Grpc.public.snk0000644000175000017500000000024012600663151020622 0ustar apollockapollock$€”$RSA1/W—©,oÍèÔ CB»Žv‡"Þ ±±^•[2¡RtåŸ,”ÄŽÜŽ}RSkŠÆQ¼áåÚ:'ü•¯óÜ`JiqAtSùH<{^ƒgVÕ²q¿$þn1•aHÀ=€D‡Ïd/ŒÀq9Nég-þ[Uê•ßÕ§÷}"ÉbÌõ Ógrpc-0.11.1/src/csharp/Grpc.Examples/0000755000175000017500000000000012600663151017436 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples/MathExamples.cs0000644000175000017500000001042012600663151022352 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading.Tasks; using Grpc.Core.Utils; namespace Math { public static class MathExamples { public static void DivExample(Math.IMathClient client) { DivReply result = client.Div(new DivArgs { Dividend = 10, Divisor = 3 }); Console.WriteLine("Div Result: " + result); } public static async Task DivAsyncExample(Math.IMathClient client) { DivReply result = await client.DivAsync(new DivArgs { Dividend = 4, Divisor = 5 }); Console.WriteLine("DivAsync Result: " + result); } public static async Task FibExample(Math.IMathClient client) { using (var call = client.Fib(new FibArgs { Limit = 5 })) { List result = await call.ResponseStream.ToListAsync(); Console.WriteLine("Fib Result: " + string.Join("|", result)); } } public static async Task SumExample(Math.IMathClient client) { var numbers = new List { new Num { Num_ = 1 }, new Num { Num_ = 2 }, new Num { Num_ = 3 } }; using (var call = client.Sum()) { await call.RequestStream.WriteAllAsync(numbers); Console.WriteLine("Sum Result: " + await call.ResponseAsync); } } public static async Task DivManyExample(Math.IMathClient client) { var divArgsList = new List { new DivArgs { Dividend = 10, Divisor = 3 }, new DivArgs { Dividend = 100, Divisor = 21 }, new DivArgs { Dividend = 7, Divisor = 2 } }; using (var call = client.DivMany()) { await call.RequestStream.WriteAllAsync(divArgsList); Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToListAsync())); } } public static async Task DependendRequestsExample(Math.IMathClient client) { var numbers = new List { new Num { Num_ = 1 }, new Num { Num_ = 2 }, new Num { Num_ = 3 } }; Num sum; using (var sumCall = client.Sum()) { await sumCall.RequestStream.WriteAllAsync(numbers); sum = await sumCall.ResponseAsync; } DivReply result = await client.DivAsync(new DivArgs { Dividend = sum.Num_, Divisor = numbers.Count }); Console.WriteLine("Avg Result: " + result); } } } grpc-0.11.1/src/csharp/Grpc.Examples/proto/0000755000175000017500000000000012600663151020601 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples/proto/math.proto0000644000175000017500000000531512600663151022623 0ustar apollockapollock // 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. syntax = "proto3"; package math; message DivArgs { int64 dividend = 1; int64 divisor = 2; } message DivReply { int64 quotient = 1; int64 remainder = 2; } message FibArgs { int64 limit = 1; } message Num { int64 num = 1; } message FibReply { int64 count = 1; } service Math { // Div divides args.dividend by args.divisor and returns the quotient and // remainder. rpc Div (DivArgs) returns (DivReply) { } // DivMany accepts an arbitrary number of division args from the client stream // and sends back the results in the reply stream. The stream continues until // the client closes its end; the server does the same after sending all the // replies. The stream ends immediately if either end aborts. rpc DivMany (stream DivArgs) returns (stream DivReply) { } // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib // generates up to limit numbers; otherwise it continues until the call is // canceled. Unlike Fib above, Fib has no final FibReply. rpc Fib (FibArgs) returns (stream Num) { } // Sum sums a stream of numbers, returning the final result once the stream // is closed. rpc Sum (stream Num) returns (Num) { } } grpc-0.11.1/src/csharp/Grpc.Examples/Settings.StyleCop0000644000175000017500000000042612600663151022724 0ustar apollockapollock Math.cs False grpc-0.11.1/src/csharp/Grpc.Examples/Math.cs0000644000175000017500000003663712600663151020675 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: math.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code using pb = global::Google.Protobuf; using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Math { namespace Proto { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Math { #region Descriptor public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; static Math() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CgptYXRoLnByb3RvEgRtYXRoIiwKB0RpdkFyZ3MSEAoIZGl2aWRlbmQYASAB", "KAMSDwoHZGl2aXNvchgCIAEoAyIvCghEaXZSZXBseRIQCghxdW90aWVudBgB", "IAEoAxIRCglyZW1haW5kZXIYAiABKAMiGAoHRmliQXJncxINCgVsaW1pdBgB", "IAEoAyISCgNOdW0SCwoDbnVtGAEgASgDIhkKCEZpYlJlcGx5Eg0KBWNvdW50", "GAEgASgDMqQBCgRNYXRoEiYKA0RpdhINLm1hdGguRGl2QXJncxoOLm1hdGgu", "RGl2UmVwbHkiABIuCgdEaXZNYW55Eg0ubWF0aC5EaXZBcmdzGg4ubWF0aC5E", "aXZSZXBseSIAKAEwARIjCgNGaWISDS5tYXRoLkZpYkFyZ3MaCS5tYXRoLk51", "bSIAMAESHwoDU3VtEgkubWF0aC5OdW0aCS5tYXRoLk51bSIAKAFiBnByb3Rv", "Mw==")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Math.DivArgs), new[]{ "Dividend", "Divisor" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Math.DivReply), new[]{ "Quotient", "Remainder" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Math.FibArgs), new[]{ "Limit" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Math.Num), new[]{ "Num_" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Math.FibReply), new[]{ "Count" }, null, null, null) })); } #endregion } } #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class DivArgs : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DivArgs()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Math.Proto.Math.Descriptor.MessageTypes[0]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public DivArgs() { OnConstruction(); } partial void OnConstruction(); public DivArgs(DivArgs other) : this() { dividend_ = other.dividend_; divisor_ = other.divisor_; } public DivArgs Clone() { return new DivArgs(this); } public const int DividendFieldNumber = 1; private long dividend_; public long Dividend { get { return dividend_; } set { dividend_ = value; } } public const int DivisorFieldNumber = 2; private long divisor_; public long Divisor { get { return divisor_; } set { divisor_ = value; } } public override bool Equals(object other) { return Equals(other as DivArgs); } public bool Equals(DivArgs other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Dividend != other.Dividend) return false; if (Divisor != other.Divisor) return false; return true; } public override int GetHashCode() { int hash = 1; if (Dividend != 0L) hash ^= Dividend.GetHashCode(); if (Divisor != 0L) hash ^= Divisor.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Dividend != 0L) { output.WriteRawTag(8); output.WriteInt64(Dividend); } if (Divisor != 0L) { output.WriteRawTag(16); output.WriteInt64(Divisor); } } public int CalculateSize() { int size = 0; if (Dividend != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Dividend); } if (Divisor != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Divisor); } return size; } public void MergeFrom(DivArgs other) { if (other == null) { return; } if (other.Dividend != 0L) { Dividend = other.Dividend; } if (other.Divisor != 0L) { Divisor = other.Divisor; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { Dividend = input.ReadInt64(); break; } case 16: { Divisor = input.ReadInt64(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class DivReply : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DivReply()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Math.Proto.Math.Descriptor.MessageTypes[1]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public DivReply() { OnConstruction(); } partial void OnConstruction(); public DivReply(DivReply other) : this() { quotient_ = other.quotient_; remainder_ = other.remainder_; } public DivReply Clone() { return new DivReply(this); } public const int QuotientFieldNumber = 1; private long quotient_; public long Quotient { get { return quotient_; } set { quotient_ = value; } } public const int RemainderFieldNumber = 2; private long remainder_; public long Remainder { get { return remainder_; } set { remainder_ = value; } } public override bool Equals(object other) { return Equals(other as DivReply); } public bool Equals(DivReply other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Quotient != other.Quotient) return false; if (Remainder != other.Remainder) return false; return true; } public override int GetHashCode() { int hash = 1; if (Quotient != 0L) hash ^= Quotient.GetHashCode(); if (Remainder != 0L) hash ^= Remainder.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Quotient != 0L) { output.WriteRawTag(8); output.WriteInt64(Quotient); } if (Remainder != 0L) { output.WriteRawTag(16); output.WriteInt64(Remainder); } } public int CalculateSize() { int size = 0; if (Quotient != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Quotient); } if (Remainder != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Remainder); } return size; } public void MergeFrom(DivReply other) { if (other == null) { return; } if (other.Quotient != 0L) { Quotient = other.Quotient; } if (other.Remainder != 0L) { Remainder = other.Remainder; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { Quotient = input.ReadInt64(); break; } case 16: { Remainder = input.ReadInt64(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class FibArgs : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FibArgs()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Math.Proto.Math.Descriptor.MessageTypes[2]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public FibArgs() { OnConstruction(); } partial void OnConstruction(); public FibArgs(FibArgs other) : this() { limit_ = other.limit_; } public FibArgs Clone() { return new FibArgs(this); } public const int LimitFieldNumber = 1; private long limit_; public long Limit { get { return limit_; } set { limit_ = value; } } public override bool Equals(object other) { return Equals(other as FibArgs); } public bool Equals(FibArgs other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Limit != other.Limit) return false; return true; } public override int GetHashCode() { int hash = 1; if (Limit != 0L) hash ^= Limit.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Limit != 0L) { output.WriteRawTag(8); output.WriteInt64(Limit); } } public int CalculateSize() { int size = 0; if (Limit != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Limit); } return size; } public void MergeFrom(FibArgs other) { if (other == null) { return; } if (other.Limit != 0L) { Limit = other.Limit; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { Limit = input.ReadInt64(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Num : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Num()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Math.Proto.Math.Descriptor.MessageTypes[3]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public Num() { OnConstruction(); } partial void OnConstruction(); public Num(Num other) : this() { num_ = other.num_; } public Num Clone() { return new Num(this); } public const int Num_FieldNumber = 1; private long num_; public long Num_ { get { return num_; } set { num_ = value; } } public override bool Equals(object other) { return Equals(other as Num); } public bool Equals(Num other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Num_ != other.Num_) return false; return true; } public override int GetHashCode() { int hash = 1; if (Num_ != 0L) hash ^= Num_.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Num_ != 0L) { output.WriteRawTag(8); output.WriteInt64(Num_); } } public int CalculateSize() { int size = 0; if (Num_ != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Num_); } return size; } public void MergeFrom(Num other) { if (other == null) { return; } if (other.Num_ != 0L) { Num_ = other.Num_; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { Num_ = input.ReadInt64(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class FibReply : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FibReply()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Math.Proto.Math.Descriptor.MessageTypes[4]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public FibReply() { OnConstruction(); } partial void OnConstruction(); public FibReply(FibReply other) : this() { count_ = other.count_; } public FibReply Clone() { return new FibReply(this); } public const int CountFieldNumber = 1; private long count_; public long Count { get { return count_; } set { count_ = value; } } public override bool Equals(object other) { return Equals(other as FibReply); } public bool Equals(FibReply other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Count != other.Count) return false; return true; } public override int GetHashCode() { int hash = 1; if (Count != 0L) hash ^= Count.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Count != 0L) { output.WriteRawTag(8); output.WriteInt64(Count); } } public int CalculateSize() { int size = 0; if (Count != 0L) { size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count); } return size; } public void MergeFrom(FibReply other) { if (other == null) { return; } if (other.Count != 0L) { Count = other.Count; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { Count = input.ReadInt64(); break; } } } } } #endregion } #endregion Designer generated code grpc-0.11.1/src/csharp/Grpc.Examples/Grpc.Examples.csproj0000644000175000017500000000575512600663151023344 0ustar apollockapollock Debug AnyCPU 10.0.0 2.0 {7DC1433E-3225-42C7-B7EA-546D56E27A4B} Library Grpc.Examples Grpc.Examples v4.5 true full false bin\Debug DEBUG; prompt 4 pdbonly true bin\Release prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk False ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core grpc-0.11.1/src/csharp/Grpc.Examples/MathServiceImpl.cs0000644000175000017500000001007412600663151023023 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; namespace Math { /// /// Implementation of MathService server /// public class MathServiceImpl : Math.IMath { public Task Div(DivArgs request, ServerCallContext context) { return Task.FromResult(DivInternal(request)); } public async Task Fib(FibArgs request, IServerStreamWriter responseStream, ServerCallContext context) { if (request.Limit <= 0) { // keep streaming the sequence until cancelled. IEnumerator fibEnumerator = FibInternal(long.MaxValue).GetEnumerator(); while (!context.CancellationToken.IsCancellationRequested && fibEnumerator.MoveNext()) { await responseStream.WriteAsync(fibEnumerator.Current); await Task.Delay(100); } } if (request.Limit > 0) { foreach (var num in FibInternal(request.Limit)) { await responseStream.WriteAsync(num); } } } public async Task Sum(IAsyncStreamReader requestStream, ServerCallContext context) { long sum = 0; await requestStream.ForEachAsync(async num => { sum += num.Num_; }); return new Num { Num_ = sum }; } public async Task DivMany(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { await requestStream.ForEachAsync(async divArgs => await responseStream.WriteAsync(DivInternal(divArgs))); } static DivReply DivInternal(DivArgs args) { long quotient = args.Dividend / args.Divisor; long remainder = args.Dividend % args.Divisor; return new DivReply { Quotient = quotient, Remainder = remainder }; } static IEnumerable FibInternal(long n) { long a = 1; yield return new Num { Num_ = a }; long b = 1; for (long i = 0; i < n - 1; i++) { long temp = a; a = b; b = temp + b; yield return new Num { Num_ = a }; } } } } grpc-0.11.1/src/csharp/Grpc.Examples/packages.config0000644000175000017500000000042712600663151022406 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Examples/Properties/0000755000175000017500000000000012600663151021572 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs0000644000175000017500000000057312600663151024521 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Examples")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.Examples/MathGrpc.cs0000644000175000017500000002011612600663151021472 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: math.proto #region Designer generated code using System; using System.Threading; using System.Threading.Tasks; using Grpc.Core; namespace Math { public static class Math { static readonly string __ServiceName = "math.Math"; static readonly Marshaller __Marshaller_DivArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom); static readonly Marshaller __Marshaller_DivReply = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom); static readonly Marshaller __Marshaller_FibArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom); static readonly Marshaller __Marshaller_Num = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom); static readonly Method __Method_Div = new Method( MethodType.Unary, __ServiceName, "Div", __Marshaller_DivArgs, __Marshaller_DivReply); static readonly Method __Method_DivMany = new Method( MethodType.DuplexStreaming, __ServiceName, "DivMany", __Marshaller_DivArgs, __Marshaller_DivReply); static readonly Method __Method_Fib = new Method( MethodType.ServerStreaming, __ServiceName, "Fib", __Marshaller_FibArgs, __Marshaller_Num); static readonly Method __Method_Sum = new Method( MethodType.ClientStreaming, __ServiceName, "Sum", __Marshaller_Num, __Marshaller_Num); // service descriptor public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor { get { return global::Math.Proto.Math.Descriptor.Services[0]; } } // client interface public interface IMathClient { global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options); AsyncUnaryCall DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncUnaryCall DivAsync(global::Math.DivArgs request, CallOptions options); AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncDuplexStreamingCall DivMany(CallOptions options); AsyncServerStreamingCall Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncServerStreamingCall Fib(global::Math.FibArgs request, CallOptions options); AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncClientStreamingCall Sum(CallOptions options); } // server-side interface public interface IMath { Task Div(global::Math.DivArgs request, ServerCallContext context); Task DivMany(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); Task Fib(global::Math.FibArgs request, IServerStreamWriter responseStream, ServerCallContext context); Task Sum(IAsyncStreamReader requestStream, ServerCallContext context); } // client stub public class MathClient : ClientBase, IMathClient { public MathClient(Channel channel) : base(channel) { } public global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } public global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options) { var call = CreateCall(__Method_Div, options); return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } public AsyncUnaryCall DivAsync(global::Math.DivArgs request, CallOptions options) { var call = CreateCall(__Method_Div, options); return Calls.AsyncUnaryCall(call, request); } public AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncDuplexStreamingCall(call); } public AsyncDuplexStreamingCall DivMany(CallOptions options) { var call = CreateCall(__Method_DivMany, options); return Calls.AsyncDuplexStreamingCall(call); } public AsyncServerStreamingCall Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncServerStreamingCall(call, request); } public AsyncServerStreamingCall Fib(global::Math.FibArgs request, CallOptions options) { var call = CreateCall(__Method_Fib, options); return Calls.AsyncServerStreamingCall(call, request); } public AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncClientStreamingCall(call); } public AsyncClientStreamingCall Sum(CallOptions options) { var call = CreateCall(__Method_Sum, options); return Calls.AsyncClientStreamingCall(call); } } // creates service definition that can be registered with a server public static ServerServiceDefinition BindService(IMath serviceImpl) { return ServerServiceDefinition.CreateBuilder(__ServiceName) .AddMethod(__Method_Div, serviceImpl.Div) .AddMethod(__Method_DivMany, serviceImpl.DivMany) .AddMethod(__Method_Fib, serviceImpl.Fib) .AddMethod(__Method_Sum, serviceImpl.Sum).Build(); } // creates a new client public static MathClient NewClient(Channel channel) { return new MathClient(channel); } } } #endregion grpc-0.11.1/src/csharp/Grpc.Examples/.gitignore0000644000175000017500000000002512600663151021423 0ustar apollockapollocktest-results bin obj grpc-0.11.1/src/csharp/Grpc.sln0000644000175000017500000002210412600663151016376 0ustar apollockapollock Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core", "Grpc.Core\Grpc.Core.csproj", "{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core.Tests", "Grpc.Core.Tests\Grpc.Core.Tests.csproj", "{86EC5CB4-4EA2-40A2-8057-86542A0353BB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.Tests", "Grpc.Examples.Tests\Grpc.Examples.Tests.csproj", "{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathClient", "Grpc.Examples.MathClient\Grpc.Examples.MathClient.csproj", "{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting", "Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj", "{C61154BA-DD4A-4838-8420-0162A28925E0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Client", "Grpc.IntegrationTesting.Client\Grpc.IntegrationTesting.Client.csproj", "{3D166931-BA2D-416E-95A3-D36E8F6E90B9}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.csproj", "{A654F3B8-E859-4E6A-B30D-227527DBEF0D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{BF62FE08-373A-43D6-9D73-41CAA38B7011}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.csproj", "{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{B5B87121-35FE-49D1-8CB1-8A91AAA398A9}" ProjectSection(SolutionItems) = preProject .nuget\packages.config = .nuget\packages.config EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.csproj", "{AA5E328A-8835-49D7-98ED-C29F2B3049F0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU ReleaseSigned|Any CPU = ReleaseSigned|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.Build.0 = Release|Any CPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/0000755000175000017500000000000012600663151021501 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Empty.cs0000644000175000017500000000571112600663151023132 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: empty.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code using pb = global::Google.Protobuf; using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Grpc.Testing { namespace Proto { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Empty { #region Descriptor public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; static Empty() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM=")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Empty), null, null, null, null) })); } #endregion } } #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Empty : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Empty()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Proto.Empty.Descriptor.MessageTypes[0]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public Empty() { OnConstruction(); } partial void OnConstruction(); public Empty(Empty other) : this() { } public Empty Clone() { return new Empty(this); } public override bool Equals(object other) { return Equals(other as Empty); } public bool Equals(Empty other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } return true; } public override int GetHashCode() { int hash = 1; return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { } public int CalculateSize() { int size = 0; return size; } public void MergeFrom(Empty other) { if (other == null) { return; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; } } } } #endregion } #endregion Designer generated code grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Messages.cs0000644000175000017500000010566112600663151023610 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: messages.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code using pb = global::Google.Protobuf; using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Grpc.Testing { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Messages { #region Descriptor public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; static Messages() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE", "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5", "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB", "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6", "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv", "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl", "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n", "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0", "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK", "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl", "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf", "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo", "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs", "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu", "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu", "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg", "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0", "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu", "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V", "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null) })); } #endregion } #region Enums public enum PayloadType { COMPRESSABLE = 0, UNCOMPRESSABLE = 1, RANDOM = 2, } #endregion #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Payload : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Payload()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[0]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public Payload() { OnConstruction(); } partial void OnConstruction(); public Payload(Payload other) : this() { type_ = other.type_; body_ = other.body_; } public Payload Clone() { return new Payload(this); } public const int TypeFieldNumber = 1; private global::Grpc.Testing.PayloadType type_ = global::Grpc.Testing.PayloadType.COMPRESSABLE; public global::Grpc.Testing.PayloadType Type { get { return type_; } set { type_ = value; } } public const int BodyFieldNumber = 2; private pb::ByteString body_ = pb::ByteString.Empty; public pb::ByteString Body { get { return body_; } set { body_ = pb::Preconditions.CheckNotNull(value, "value"); } } public override bool Equals(object other) { return Equals(other as Payload); } public bool Equals(Payload other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Type != other.Type) return false; if (Body != other.Body) return false; return true; } public override int GetHashCode() { int hash = 1; if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= Type.GetHashCode(); if (Body.Length != 0) hash ^= Body.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) { output.WriteRawTag(8); output.WriteEnum((int) Type); } if (Body.Length != 0) { output.WriteRawTag(18); output.WriteBytes(Body); } } public int CalculateSize() { int size = 0; if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); } if (Body.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Body); } return size; } public void MergeFrom(Payload other) { if (other == null) { return; } if (other.Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) { Type = other.Type; } if (other.Body.Length != 0) { Body = other.Body; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { type_ = (global::Grpc.Testing.PayloadType) input.ReadEnum(); break; } case 18: { Body = input.ReadBytes(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SimpleRequest : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SimpleRequest()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public SimpleRequest() { OnConstruction(); } partial void OnConstruction(); public SimpleRequest(SimpleRequest other) : this() { responseType_ = other.responseType_; responseSize_ = other.responseSize_; Payload = other.payload_ != null ? other.Payload.Clone() : null; fillUsername_ = other.fillUsername_; fillOauthScope_ = other.fillOauthScope_; } public SimpleRequest Clone() { return new SimpleRequest(this); } public const int ResponseTypeFieldNumber = 1; private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE; public global::Grpc.Testing.PayloadType ResponseType { get { return responseType_; } set { responseType_ = value; } } public const int ResponseSizeFieldNumber = 2; private int responseSize_; public int ResponseSize { get { return responseSize_; } set { responseSize_ = value; } } public const int PayloadFieldNumber = 3; private global::Grpc.Testing.Payload payload_; public global::Grpc.Testing.Payload Payload { get { return payload_; } set { payload_ = value; } } public const int FillUsernameFieldNumber = 4; private bool fillUsername_; public bool FillUsername { get { return fillUsername_; } set { fillUsername_ = value; } } public const int FillOauthScopeFieldNumber = 5; private bool fillOauthScope_; public bool FillOauthScope { get { return fillOauthScope_; } set { fillOauthScope_ = value; } } public override bool Equals(object other) { return Equals(other as SimpleRequest); } public bool Equals(SimpleRequest other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (ResponseType != other.ResponseType) return false; if (ResponseSize != other.ResponseSize) return false; if (!object.Equals(Payload, other.Payload)) return false; if (FillUsername != other.FillUsername) return false; if (FillOauthScope != other.FillOauthScope) return false; return true; } public override int GetHashCode() { int hash = 1; if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode(); if (ResponseSize != 0) hash ^= ResponseSize.GetHashCode(); if (payload_ != null) hash ^= Payload.GetHashCode(); if (FillUsername != false) hash ^= FillUsername.GetHashCode(); if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { output.WriteRawTag(8); output.WriteEnum((int) ResponseType); } if (ResponseSize != 0) { output.WriteRawTag(16); output.WriteInt32(ResponseSize); } if (payload_ != null) { output.WriteRawTag(26); output.WriteMessage(Payload); } if (FillUsername != false) { output.WriteRawTag(32); output.WriteBool(FillUsername); } if (FillOauthScope != false) { output.WriteRawTag(40); output.WriteBool(FillOauthScope); } } public int CalculateSize() { int size = 0; if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType); } if (ResponseSize != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(ResponseSize); } if (payload_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } if (FillUsername != false) { size += 1 + 1; } if (FillOauthScope != false) { size += 1 + 1; } return size; } public void MergeFrom(SimpleRequest other) { if (other == null) { return; } if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { ResponseType = other.ResponseType; } if (other.ResponseSize != 0) { ResponseSize = other.ResponseSize; } if (other.payload_ != null) { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } Payload.MergeFrom(other.Payload); } if (other.FillUsername != false) { FillUsername = other.FillUsername; } if (other.FillOauthScope != false) { FillOauthScope = other.FillOauthScope; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { responseType_ = (global::Grpc.Testing.PayloadType) input.ReadEnum(); break; } case 16: { ResponseSize = input.ReadInt32(); break; } case 26: { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } input.ReadMessage(payload_); break; } case 32: { FillUsername = input.ReadBool(); break; } case 40: { FillOauthScope = input.ReadBool(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SimpleResponse : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SimpleResponse()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public SimpleResponse() { OnConstruction(); } partial void OnConstruction(); public SimpleResponse(SimpleResponse other) : this() { Payload = other.payload_ != null ? other.Payload.Clone() : null; username_ = other.username_; oauthScope_ = other.oauthScope_; } public SimpleResponse Clone() { return new SimpleResponse(this); } public const int PayloadFieldNumber = 1; private global::Grpc.Testing.Payload payload_; public global::Grpc.Testing.Payload Payload { get { return payload_; } set { payload_ = value; } } public const int UsernameFieldNumber = 2; private string username_ = ""; public string Username { get { return username_; } set { username_ = pb::Preconditions.CheckNotNull(value, "value"); } } public const int OauthScopeFieldNumber = 3; private string oauthScope_ = ""; public string OauthScope { get { return oauthScope_; } set { oauthScope_ = pb::Preconditions.CheckNotNull(value, "value"); } } public override bool Equals(object other) { return Equals(other as SimpleResponse); } public bool Equals(SimpleResponse other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (!object.Equals(Payload, other.Payload)) return false; if (Username != other.Username) return false; if (OauthScope != other.OauthScope) return false; return true; } public override int GetHashCode() { int hash = 1; if (payload_ != null) hash ^= Payload.GetHashCode(); if (Username.Length != 0) hash ^= Username.GetHashCode(); if (OauthScope.Length != 0) hash ^= OauthScope.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (payload_ != null) { output.WriteRawTag(10); output.WriteMessage(Payload); } if (Username.Length != 0) { output.WriteRawTag(18); output.WriteString(Username); } if (OauthScope.Length != 0) { output.WriteRawTag(26); output.WriteString(OauthScope); } } public int CalculateSize() { int size = 0; if (payload_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } if (Username.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Username); } if (OauthScope.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(OauthScope); } return size; } public void MergeFrom(SimpleResponse other) { if (other == null) { return; } if (other.payload_ != null) { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } Payload.MergeFrom(other.Payload); } if (other.Username.Length != 0) { Username = other.Username; } if (other.OauthScope.Length != 0) { OauthScope = other.OauthScope; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 10: { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } input.ReadMessage(payload_); break; } case 18: { Username = input.ReadString(); break; } case 26: { OauthScope = input.ReadString(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingInputCallRequest : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingInputCallRequest()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public StreamingInputCallRequest() { OnConstruction(); } partial void OnConstruction(); public StreamingInputCallRequest(StreamingInputCallRequest other) : this() { Payload = other.payload_ != null ? other.Payload.Clone() : null; } public StreamingInputCallRequest Clone() { return new StreamingInputCallRequest(this); } public const int PayloadFieldNumber = 1; private global::Grpc.Testing.Payload payload_; public global::Grpc.Testing.Payload Payload { get { return payload_; } set { payload_ = value; } } public override bool Equals(object other) { return Equals(other as StreamingInputCallRequest); } public bool Equals(StreamingInputCallRequest other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (!object.Equals(Payload, other.Payload)) return false; return true; } public override int GetHashCode() { int hash = 1; if (payload_ != null) hash ^= Payload.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (payload_ != null) { output.WriteRawTag(10); output.WriteMessage(Payload); } } public int CalculateSize() { int size = 0; if (payload_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } return size; } public void MergeFrom(StreamingInputCallRequest other) { if (other == null) { return; } if (other.payload_ != null) { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } Payload.MergeFrom(other.Payload); } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 10: { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } input.ReadMessage(payload_); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingInputCallResponse : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingInputCallResponse()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public StreamingInputCallResponse() { OnConstruction(); } partial void OnConstruction(); public StreamingInputCallResponse(StreamingInputCallResponse other) : this() { aggregatedPayloadSize_ = other.aggregatedPayloadSize_; } public StreamingInputCallResponse Clone() { return new StreamingInputCallResponse(this); } public const int AggregatedPayloadSizeFieldNumber = 1; private int aggregatedPayloadSize_; public int AggregatedPayloadSize { get { return aggregatedPayloadSize_; } set { aggregatedPayloadSize_ = value; } } public override bool Equals(object other) { return Equals(other as StreamingInputCallResponse); } public bool Equals(StreamingInputCallResponse other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (AggregatedPayloadSize != other.AggregatedPayloadSize) return false; return true; } public override int GetHashCode() { int hash = 1; if (AggregatedPayloadSize != 0) hash ^= AggregatedPayloadSize.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (AggregatedPayloadSize != 0) { output.WriteRawTag(8); output.WriteInt32(AggregatedPayloadSize); } } public int CalculateSize() { int size = 0; if (AggregatedPayloadSize != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(AggregatedPayloadSize); } return size; } public void MergeFrom(StreamingInputCallResponse other) { if (other == null) { return; } if (other.AggregatedPayloadSize != 0) { AggregatedPayloadSize = other.AggregatedPayloadSize; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { AggregatedPayloadSize = input.ReadInt32(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ResponseParameters : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResponseParameters()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public ResponseParameters() { OnConstruction(); } partial void OnConstruction(); public ResponseParameters(ResponseParameters other) : this() { size_ = other.size_; intervalUs_ = other.intervalUs_; } public ResponseParameters Clone() { return new ResponseParameters(this); } public const int SizeFieldNumber = 1; private int size_; public int Size { get { return size_; } set { size_ = value; } } public const int IntervalUsFieldNumber = 2; private int intervalUs_; public int IntervalUs { get { return intervalUs_; } set { intervalUs_ = value; } } public override bool Equals(object other) { return Equals(other as ResponseParameters); } public bool Equals(ResponseParameters other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Size != other.Size) return false; if (IntervalUs != other.IntervalUs) return false; return true; } public override int GetHashCode() { int hash = 1; if (Size != 0) hash ^= Size.GetHashCode(); if (IntervalUs != 0) hash ^= IntervalUs.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (Size != 0) { output.WriteRawTag(8); output.WriteInt32(Size); } if (IntervalUs != 0) { output.WriteRawTag(16); output.WriteInt32(IntervalUs); } } public int CalculateSize() { int size = 0; if (Size != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(Size); } if (IntervalUs != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(IntervalUs); } return size; } public void MergeFrom(ResponseParameters other) { if (other == null) { return; } if (other.Size != 0) { Size = other.Size; } if (other.IntervalUs != 0) { IntervalUs = other.IntervalUs; } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { Size = input.ReadInt32(); break; } case 16: { IntervalUs = input.ReadInt32(); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingOutputCallRequest : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingOutputCallRequest()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public StreamingOutputCallRequest() { OnConstruction(); } partial void OnConstruction(); public StreamingOutputCallRequest(StreamingOutputCallRequest other) : this() { responseType_ = other.responseType_; responseParameters_ = other.responseParameters_.Clone(); Payload = other.payload_ != null ? other.Payload.Clone() : null; } public StreamingOutputCallRequest Clone() { return new StreamingOutputCallRequest(this); } public const int ResponseTypeFieldNumber = 1; private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE; public global::Grpc.Testing.PayloadType ResponseType { get { return responseType_; } set { responseType_ = value; } } public const int ResponseParametersFieldNumber = 2; private static readonly pb::FieldCodec _repeated_responseParameters_codec = pb::FieldCodec.ForMessage(18, global::Grpc.Testing.ResponseParameters.Parser); private readonly pbc::RepeatedField responseParameters_ = new pbc::RepeatedField(); public pbc::RepeatedField ResponseParameters { get { return responseParameters_; } } public const int PayloadFieldNumber = 3; private global::Grpc.Testing.Payload payload_; public global::Grpc.Testing.Payload Payload { get { return payload_; } set { payload_ = value; } } public override bool Equals(object other) { return Equals(other as StreamingOutputCallRequest); } public bool Equals(StreamingOutputCallRequest other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (ResponseType != other.ResponseType) return false; if(!responseParameters_.Equals(other.responseParameters_)) return false; if (!object.Equals(Payload, other.Payload)) return false; return true; } public override int GetHashCode() { int hash = 1; if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode(); hash ^= responseParameters_.GetHashCode(); if (payload_ != null) hash ^= Payload.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { output.WriteRawTag(8); output.WriteEnum((int) ResponseType); } responseParameters_.WriteTo(output, _repeated_responseParameters_codec); if (payload_ != null) { output.WriteRawTag(26); output.WriteMessage(Payload); } } public int CalculateSize() { int size = 0; if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType); } size += responseParameters_.CalculateSize(_repeated_responseParameters_codec); if (payload_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } return size; } public void MergeFrom(StreamingOutputCallRequest other) { if (other == null) { return; } if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { ResponseType = other.ResponseType; } responseParameters_.Add(other.responseParameters_); if (other.payload_ != null) { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } Payload.MergeFrom(other.Payload); } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 8: { responseType_ = (global::Grpc.Testing.PayloadType) input.ReadEnum(); break; } case 18: { responseParameters_.AddEntriesFrom(input, _repeated_responseParameters_codec); break; } case 26: { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } input.ReadMessage(payload_); break; } } } } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingOutputCallResponse : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingOutputCallResponse()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } public StreamingOutputCallResponse() { OnConstruction(); } partial void OnConstruction(); public StreamingOutputCallResponse(StreamingOutputCallResponse other) : this() { Payload = other.payload_ != null ? other.Payload.Clone() : null; } public StreamingOutputCallResponse Clone() { return new StreamingOutputCallResponse(this); } public const int PayloadFieldNumber = 1; private global::Grpc.Testing.Payload payload_; public global::Grpc.Testing.Payload Payload { get { return payload_; } set { payload_ = value; } } public override bool Equals(object other) { return Equals(other as StreamingOutputCallResponse); } public bool Equals(StreamingOutputCallResponse other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (!object.Equals(Payload, other.Payload)) return false; return true; } public override int GetHashCode() { int hash = 1; if (payload_ != null) hash ^= Payload.GetHashCode(); return hash; } public override string ToString() { return pb::JsonFormatter.Default.Format(this); } public void WriteTo(pb::CodedOutputStream output) { if (payload_ != null) { output.WriteRawTag(10); output.WriteMessage(Payload); } } public int CalculateSize() { int size = 0; if (payload_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } return size; } public void MergeFrom(StreamingOutputCallResponse other) { if (other == null) { return; } if (other.payload_ != null) { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } Payload.MergeFrom(other.Payload); } } public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: input.SkipLastField(); break; case 10: { if (payload_ == null) { payload_ = new global::Grpc.Testing.Payload(); } input.ReadMessage(payload_); break; } } } } } #endregion } #endregion Designer generated code grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs0000644000175000017500000001032412600663151026636 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting { /// /// Runs interop tests in-process. /// public class InteropClientServerTest { const string Host = "localhost"; Server server; Channel channel; TestService.ITestServiceClient client; [TestFixtureSetUp] public void Init() { server = new Server { Services = { TestService.BindService(new TestServiceImpl()) }, Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateTestServerCredentials() } } }; server.Start(); var options = new List { new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) }; int port = server.Ports.Single().BoundPort; channel = new Channel(Host, port, TestCredentials.CreateTestClientCredentials(true), options); client = TestService.NewClient(channel); } [TestFixtureTearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void EmptyUnary() { InteropClient.RunEmptyUnary(client); } [Test] public void LargeUnary() { InteropClient.RunLargeUnary(client); } [Test] public async Task ClientStreaming() { await InteropClient.RunClientStreamingAsync(client); } [Test] public async Task ServerStreaming() { await InteropClient.RunServerStreamingAsync(client); } [Test] public async Task PingPong() { await InteropClient.RunPingPongAsync(client); } [Test] public async Task EmptyStream() { await InteropClient.RunEmptyStreamAsync(client); } [Test] public async Task CancelAfterBegin() { await InteropClient.RunCancelAfterBeginAsync(client); } [Test] public async Task CancelAfterFirstResponse() { await InteropClient.RunCancelAfterFirstResponseAsync(client); } [Test] public async Task TimeoutOnSleepingServerAsync() { await InteropClient.RunTimeoutOnSleepingServerAsync(client); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/proto/0000755000175000017500000000000012600663151022644 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting/proto/empty.proto0000644000175000017500000000360312600663151025071 0ustar apollockapollock // 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. syntax = "proto3"; package grpc.testing; // An empty message that you can re-use to avoid defining duplicated empty // messages in your project. A typical example is to use it as argument or the // return value of a service API. For instance: // // service Foo { // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; // }; // message Empty {} grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/proto/test.proto0000644000175000017500000000644012600663151024714 0ustar apollockapollock // 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. // An integration test service that covers all the method signature permutations // of unary/streaming requests/responses. syntax = "proto3"; import "empty.proto"; import "messages.proto"; package grpc.testing; // A simple service to test the various types of RPCs and experiment with // performance with various types of payload. service TestService { // One empty request followed by one empty response. rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); // One request followed by one response. // TODO(Issue 527): Describe required server behavior. rpc UnaryCall(SimpleRequest) returns (SimpleResponse); // One request followed by a sequence of responses (streamed download). // The server returns the payload with client desired type and sizes. rpc StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); // A sequence of requests followed by one response (streamed upload). // The server returns the aggregated size of client payload as the result. rpc StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse); // A sequence of requests with each request served by the server immediately. // As one request could lead to multiple responses, this interface // demonstrates the idea of full duplexing. rpc FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); // A sequence of requests followed by a sequence of responses. // The server buffers all the client requests and then serves them in order. A // stream of responses are returned to the client when the server starts with // first request. rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/proto/messages.proto0000644000175000017500000001062112600663151025540 0ustar apollockapollock // 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. // Message definitions to be used by integration test service definitions. syntax = "proto3"; package grpc.testing; // The type of payload that should be returned. enum PayloadType { // Compressable text format. COMPRESSABLE = 0; // Uncompressable binary format. UNCOMPRESSABLE = 1; // Randomly chosen from all other formats defined in this enum. RANDOM = 2; } // A block of data, to simply increase gRPC message size. message Payload { // The type of data in body. PayloadType type = 1; // Primary contents of payload. bytes body = 2; } // Unary request. message SimpleRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, server randomly chooses one from other formats. PayloadType response_type = 1; // Desired payload size in the response from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. int32 response_size = 2; // Optional input payload sent along with the request. Payload payload = 3; // Whether SimpleResponse should include username. bool fill_username = 4; // Whether SimpleResponse should include OAuth scope. bool fill_oauth_scope = 5; } // Unary response, as configured by the request. message SimpleResponse { // Payload to increase message size. Payload payload = 1; // The user the request came from, for verifying authentication was // successful when the client expected it. string username = 2; // OAuth scope. string oauth_scope = 3; } // Client-streaming request. message StreamingInputCallRequest { // Optional input payload sent along with the request. Payload payload = 1; // Not expecting any payload from the response. } // Client-streaming response. message StreamingInputCallResponse { // Aggregated size of payloads received from the client. int32 aggregated_payload_size = 1; } // Configuration for a particular response. message ResponseParameters { // Desired payload sizes in responses from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. int32 size = 1; // Desired interval between consecutive responses in the response stream in // microseconds. int32 interval_us = 2; } // Server-streaming request. message StreamingOutputCallRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, the payload from each response in the stream // might be of different types. This is to simulate a mixed type of payload // stream. PayloadType response_type = 1; // Configuration for each expected response message. repeated ResponseParameters response_parameters = 2; // Optional input payload sent along with the request. Payload payload = 3; } // Server-streaming response, as configured by the request and parameters. message StreamingOutputCallResponse { // Payload to increase response size. Payload payload = 1; } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop0000644000175000017500000000050012600663151024760 0ustar apollockapollock Messages.cs Empty.cs False grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs0000644000175000017500000000623012600663151025126 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.IntegrationTesting { /// /// SSL Credentials for testing. /// public static class TestCredentials { public const string DefaultHostOverride = "foo.test.google.fr"; public const string ClientCertAuthorityPath = "data/ca.pem"; public const string ClientCertAuthorityEnvName = "SSL_CERT_FILE"; public const string ServerCertChainPath = "data/server1.pem"; public const string ServerPrivateKeyPath = "data/server1.key"; public static SslCredentials CreateTestClientCredentials(bool useTestCa) { string caPath = ClientCertAuthorityPath; if (!useTestCa) { caPath = Environment.GetEnvironmentVariable(ClientCertAuthorityEnvName); if (string.IsNullOrEmpty(caPath)) { throw new ArgumentException("CA path environment variable is not set."); } } return new SslCredentials(File.ReadAllText(caPath)); } public static SslServerCredentials CreateTestServerCredentials() { var keyCertPair = new KeyCertificatePair( File.ReadAllText(ServerCertChainPath), File.ReadAllText(ServerPrivateKeyPath)); return new SslServerCredentials(new[] { keyCertPair }); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/InteropServer.cs0000644000175000017500000000730512600663151024644 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; using CommandLine; using CommandLine.Text; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting { public class InteropServer { private class ServerOptions { [Option("port", DefaultValue = 8070)] public int Port { get; set; } [Option("use_tls")] public bool UseTls { get; set; } [HelpOption] public string GetUsage() { var help = new HelpText { Heading = "gRPC C# interop testing server", AddDashesToOption = true }; help.AddPreOptionsLine("Usage:"); help.AddOptions(this); return help; } } ServerOptions options; private InteropServer(ServerOptions options) { this.options = options; } public static void Run(string[] args) { var options = new ServerOptions(); if (!Parser.Default.ParseArguments(args, options)) { Environment.Exit(1); } var interopServer = new InteropServer(options); interopServer.Run(); } private void Run() { var server = new Server { Services = { TestService.BindService(new TestServiceImpl()) } }; string host = "0.0.0.0"; int port = options.Port; if (options.UseTls) { server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials()); } else { server.Ports.Add(host, options.Port, ServerCredentials.Insecure); } Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port)); server.Start(); server.ShutdownTask.Wait(); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Test.cs0000644000175000017500000000420512600663151022750 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: test.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code using pb = global::Google.Protobuf; using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Grpc.Testing { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Test { #region Descriptor public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; static Test() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz", "YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw", "Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5", "Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0", "aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n", "cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj", "LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry", "ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0", "Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs", "UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T", "dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl", "YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs", "EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku", "Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi", "BnByb3RvMw==")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, }, new pbr::GeneratedCodeInfo(null, null)); } #endregion } } #endregion Designer generated code grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj0000644000175000017500000001753012600663151027444 0ustar apollockapollock Debug AnyCPU {C61154BA-DD4A-4838-8420-0162A28925E0} Library Grpc.IntegrationTesting Grpc.IntegrationTesting v4.5 6566287f true full false bin\Debug DEBUG; prompt 4 AnyCPU pdbonly true bin\Release prompt 4 AnyCPU pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk False ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll ..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll False ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll False ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll False ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll False ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll False ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll ..\packages\NUnit.2.6.4\lib\nunit.framework.dll ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA} Grpc.Auth PreserveNewest PreserveNewest PreserveNewest PreserveNewest This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/data/0000755000175000017500000000000012600663151022412 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting/data/server1.pem0000644000175000017500000000170412600663151024506 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= -----END CERTIFICATE----- grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/data/ca.pem0000644000175000017500000000152712600663151023505 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 +L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG Dfcog5wrJytaQ6UA0wE= -----END CERTIFICATE----- grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/data/README0000644000175000017500000000002112600663151023263 0ustar apollockapollockCONFIRMEDTESTKEY grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/data/server1.key0000644000175000017500000000162012600663151024512 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf 3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR 81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe F98XJ7tIFfJq -----END PRIVATE KEY----- grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs0000644000175000017500000003676512600663151023604 0ustar apollockapollock// Generated by the protocol buffer compiler. DO NOT EDIT! // source: test.proto #region Designer generated code using System; using System.Threading; using System.Threading.Tasks; using Grpc.Core; namespace Grpc.Testing { public static class TestService { static readonly string __ServiceName = "grpc.testing.TestService"; static readonly Marshaller __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom); static readonly Marshaller __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom); static readonly Marshaller __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom); static readonly Marshaller __Marshaller_StreamingOutputCallRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom); static readonly Marshaller __Marshaller_StreamingOutputCallResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom); static readonly Marshaller __Marshaller_StreamingInputCallRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom); static readonly Marshaller __Marshaller_StreamingInputCallResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom); static readonly Method __Method_EmptyCall = new Method( MethodType.Unary, __ServiceName, "EmptyCall", __Marshaller_Empty, __Marshaller_Empty); static readonly Method __Method_UnaryCall = new Method( MethodType.Unary, __ServiceName, "UnaryCall", __Marshaller_SimpleRequest, __Marshaller_SimpleResponse); static readonly Method __Method_StreamingOutputCall = new Method( MethodType.ServerStreaming, __ServiceName, "StreamingOutputCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); static readonly Method __Method_StreamingInputCall = new Method( MethodType.ClientStreaming, __ServiceName, "StreamingInputCall", __Marshaller_StreamingInputCallRequest, __Marshaller_StreamingInputCallResponse); static readonly Method __Method_FullDuplexCall = new Method( MethodType.DuplexStreaming, __ServiceName, "FullDuplexCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); static readonly Method __Method_HalfDuplexCall = new Method( MethodType.DuplexStreaming, __ServiceName, "HalfDuplexCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); // service descriptor public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor { get { return global::Grpc.Testing.Test.Descriptor.Services[0]; } } // client interface public interface ITestServiceClient { global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options); AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options); global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options); AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options); AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options); AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncClientStreamingCall StreamingInputCall(CallOptions options); AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncDuplexStreamingCall FullDuplexCall(CallOptions options); AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncDuplexStreamingCall HalfDuplexCall(CallOptions options); } // server-side interface public interface ITestService { Task EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context); Task UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context); Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter responseStream, ServerCallContext context); Task StreamingInputCall(IAsyncStreamReader requestStream, ServerCallContext context); Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); Task HalfDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); } // client stub public class TestServiceClient : ClientBase, ITestServiceClient { public TestServiceClient(Channel channel) : base(channel) { } public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options) { var call = CreateCall(__Method_EmptyCall, options); return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } public AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options) { var call = CreateCall(__Method_EmptyCall, options); return Calls.AsyncUnaryCall(call, request); } public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options) { var call = CreateCall(__Method_UnaryCall, options); return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } public AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options) { var call = CreateCall(__Method_UnaryCall, options); return Calls.AsyncUnaryCall(call, request); } public AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncServerStreamingCall(call, request); } public AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options) { var call = CreateCall(__Method_StreamingOutputCall, options); return Calls.AsyncServerStreamingCall(call, request); } public AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncClientStreamingCall(call); } public AsyncClientStreamingCall StreamingInputCall(CallOptions options) { var call = CreateCall(__Method_StreamingInputCall, options); return Calls.AsyncClientStreamingCall(call); } public AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncDuplexStreamingCall(call); } public AsyncDuplexStreamingCall FullDuplexCall(CallOptions options) { var call = CreateCall(__Method_FullDuplexCall, options); return Calls.AsyncDuplexStreamingCall(call); } public AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncDuplexStreamingCall(call); } public AsyncDuplexStreamingCall HalfDuplexCall(CallOptions options) { var call = CreateCall(__Method_HalfDuplexCall, options); return Calls.AsyncDuplexStreamingCall(call); } } // creates service definition that can be registered with a server public static ServerServiceDefinition BindService(ITestService serviceImpl) { return ServerServiceDefinition.CreateBuilder(__ServiceName) .AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall) .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall) .AddMethod(__Method_StreamingOutputCall, serviceImpl.StreamingOutputCall) .AddMethod(__Method_StreamingInputCall, serviceImpl.StreamingInputCall) .AddMethod(__Method_FullDuplexCall, serviceImpl.FullDuplexCall) .AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build(); } // creates a new client public static TestServiceClient NewClient(Channel channel) { return new TestServiceClient(channel); } } } #endregion grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/packages.config0000644000175000017500000000204012600663151024442 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs0000644000175000017500000000722612600663151025616 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting { /// /// Test SSL credentials where server authenticates client /// and client authenticates the server. /// public class SslCredentialsTest { const string Host = "localhost"; Server server; Channel channel; TestService.ITestServiceClient client; [TestFixtureSetUp] public void Init() { var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath); var keyCertPair = new KeyCertificatePair( File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)); var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true); var clientCredentials = new SslCredentials(rootCert, keyCertPair); server = new Server { Services = { TestService.BindService(new TestServiceImpl()) }, Ports = { { Host, ServerPort.PickUnused, serverCredentials } } }; server.Start(); var options = new List { new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) }; channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options); client = TestService.NewClient(channel); } [TestFixtureTearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } [Test] public void AuthenticatedClientAndServer() { var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 }); Assert.AreEqual(10, response.Payload.Body.Length); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs0000644000175000017500000002532012600663151025106 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Grpc.Core; namespace grpc.testing { /// /// TestService (this is handwritten version of code that will normally be generated). /// public class TestServiceGrpc { static readonly string ServiceName = "/grpc.testing.TestService"; static readonly Marshaller EmptyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Empty.ParseFrom); static readonly Marshaller SimpleRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleRequest.ParseFrom); static readonly Marshaller SimpleResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleResponse.ParseFrom); static readonly Marshaller StreamingOutputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallRequest.ParseFrom); static readonly Marshaller StreamingOutputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallResponse.ParseFrom); static readonly Marshaller StreamingInputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallRequest.ParseFrom); static readonly Marshaller StreamingInputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallResponse.ParseFrom); static readonly Method EmptyCallMethod = new Method( MethodType.Unary, "EmptyCall", EmptyMarshaller, EmptyMarshaller); static readonly Method UnaryCallMethod = new Method( MethodType.Unary, "UnaryCall", SimpleRequestMarshaller, SimpleResponseMarshaller); static readonly Method StreamingOutputCallMethod = new Method( MethodType.ServerStreaming, "StreamingOutputCall", StreamingOutputCallRequestMarshaller, StreamingOutputCallResponseMarshaller); static readonly Method StreamingInputCallMethod = new Method( MethodType.ClientStreaming, "StreamingInputCall", StreamingInputCallRequestMarshaller, StreamingInputCallResponseMarshaller); static readonly Method FullDuplexCallMethod = new Method( MethodType.DuplexStreaming, "FullDuplexCall", StreamingOutputCallRequestMarshaller, StreamingOutputCallResponseMarshaller); static readonly Method HalfDuplexCallMethod = new Method( MethodType.DuplexStreaming, "HalfDuplexCall", StreamingOutputCallRequestMarshaller, StreamingOutputCallResponseMarshaller); public interface ITestServiceClient { Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken)); Task EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken)); SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken)); Task UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken)); AsyncServerStreamingCall StreamingOutputCall(StreamingOutputCallRequest request, CancellationToken token = default(CancellationToken)); AsyncClientStreamingCall StreamingInputCall(CancellationToken token = default(CancellationToken)); AsyncDuplexStreamingCall FullDuplexCall(CancellationToken token = default(CancellationToken)); AsyncDuplexStreamingCall HalfDuplexCall(CancellationToken token = default(CancellationToken)); } public class TestServiceClientStub : AbstractStub, ITestServiceClient { public TestServiceClientStub(Channel channel) : base(channel, StubConfiguration.Default) { } public TestServiceClientStub(Channel channel, StubConfiguration config) : base(channel, config) { } public Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, EmptyCallMethod); return Calls.BlockingUnaryCall(call, request, token); } public Task EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, EmptyCallMethod); return Calls.AsyncUnaryCall(call, request, token); } public SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, UnaryCallMethod); return Calls.BlockingUnaryCall(call, request, token); } public Task UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, UnaryCallMethod); return Calls.AsyncUnaryCall(call, request, token); } public AsyncServerStreamingCall StreamingOutputCall(StreamingOutputCallRequest request, CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, StreamingOutputCallMethod); return Calls.AsyncServerStreamingCall(call, request, token); } public AsyncClientStreamingCall StreamingInputCall(CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, StreamingInputCallMethod); return Calls.AsyncClientStreamingCall(call, token); } public AsyncDuplexStreamingCall FullDuplexCall(CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, FullDuplexCallMethod); return Calls.AsyncDuplexStreamingCall(call, token); } public AsyncDuplexStreamingCall HalfDuplexCall(CancellationToken token = default(CancellationToken)) { var call = CreateCall(ServiceName, HalfDuplexCallMethod); return Calls.AsyncDuplexStreamingCall(call, token); } } // server-side interface public interface ITestService { Task EmptyCall(ServerCallContext context, Empty request); Task UnaryCall(ServerCallContext context, SimpleRequest request); Task StreamingOutputCall(ServerCallContext context, StreamingOutputCallRequest request, IServerStreamWriter responseStream); Task StreamingInputCall(ServerCallContext context, IAsyncStreamReader requestStream); Task FullDuplexCall(ServerCallContext context, IAsyncStreamReader requestStream, IServerStreamWriter responseStream); Task HalfDuplexCall(ServerCallContext context, IAsyncStreamReader requestStream, IServerStreamWriter responseStream); } public static ServerServiceDefinition BindService(ITestService serviceImpl) { return ServerServiceDefinition.CreateBuilder(ServiceName) .AddMethod(EmptyCallMethod, serviceImpl.EmptyCall) .AddMethod(UnaryCallMethod, serviceImpl.UnaryCall) .AddMethod(StreamingOutputCallMethod, serviceImpl.StreamingOutputCall) .AddMethod(StreamingInputCallMethod, serviceImpl.StreamingInputCall) .AddMethod(FullDuplexCallMethod, serviceImpl.FullDuplexCall) .AddMethod(HalfDuplexCallMethod, serviceImpl.HalfDuplexCall) .Build(); } public static ITestServiceClient NewStub(Channel channel) { return new TestServiceClientStub(channel); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/app.config0000644000175000017500000000162112600663151023450 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Properties/0000755000175000017500000000000012600663151023635 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs0000644000175000017500000000060512600663151026560 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.IntegrationTesting")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/.gitignore0000644000175000017500000000000712600663151023466 0ustar apollockapollockbin objgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting/InteropClient.cs0000644000175000017500000004776012600663151024625 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using CommandLine; using Google.Apis.Auth.OAuth2; using Google.Protobuf; using Grpc.Auth; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; using NUnit.Framework; using CommandLine.Text; using System.IO; namespace Grpc.IntegrationTesting { public class InteropClient { private class ClientOptions { [Option("server_host", DefaultValue = "127.0.0.1")] public string ServerHost { get; set; } [Option("server_host_override", DefaultValue = TestCredentials.DefaultHostOverride)] public string ServerHostOverride { get; set; } [Option("server_port", Required = true)] public int ServerPort { get; set; } [Option("test_case", DefaultValue = "large_unary")] public string TestCase { get; set; } [Option("use_tls")] public bool UseTls { get; set; } [Option("use_test_ca")] public bool UseTestCa { get; set; } [Option("default_service_account", Required = false)] public string DefaultServiceAccount { get; set; } [Option("oauth_scope", Required = false)] public string OAuthScope { get; set; } [Option("service_account_key_file", Required = false)] public string ServiceAccountKeyFile { get; set; } [HelpOption] public string GetUsage() { var help = new HelpText { Heading = "gRPC C# interop testing client", AddDashesToOption = true }; help.AddPreOptionsLine("Usage:"); help.AddOptions(this); return help; } } ClientOptions options; private InteropClient(ClientOptions options) { this.options = options; } public static void Run(string[] args) { var options = new ClientOptions(); if (!Parser.Default.ParseArguments(args, options)) { Environment.Exit(1); } var interopClient = new InteropClient(options); interopClient.Run().Wait(); } private async Task Run() { var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; List channelOptions = null; if (!string.IsNullOrEmpty(options.ServerHostOverride)) { channelOptions = new List { new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) }; } Console.WriteLine(options.ServerHost); Console.WriteLine(options.ServerPort); var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); TestService.TestServiceClient client = new TestService.TestServiceClient(channel); await RunTestCaseAsync(client, options); await channel.ShutdownAsync(); } private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options) { switch (options.TestCase) { case "empty_unary": RunEmptyUnary(client); break; case "large_unary": RunLargeUnary(client); break; case "client_streaming": await RunClientStreamingAsync(client); break; case "server_streaming": await RunServerStreamingAsync(client); break; case "ping_pong": await RunPingPongAsync(client); break; case "empty_stream": await RunEmptyStreamAsync(client); break; case "compute_engine_creds": await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); break; case "jwt_token_creds": await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount); break; case "oauth2_auth_token": await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope); break; case "per_rpc_creds": await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); break; case "cancel_after_begin": await RunCancelAfterBeginAsync(client); break; case "cancel_after_first_response": await RunCancelAfterFirstResponseAsync(client); break; case "timeout_on_sleeping_server": await RunTimeoutOnSleepingServerAsync(client); break; case "benchmark_empty_unary": RunBenchmarkEmptyUnary(client); break; default: throw new ArgumentException("Unknown test case " + options.TestCase); } } public static void RunEmptyUnary(TestService.ITestServiceClient client) { Console.WriteLine("running empty_unary"); var response = client.EmptyCall(new Empty()); Assert.IsNotNull(response); Console.WriteLine("Passed!"); } public static void RunLargeUnary(TestService.ITestServiceClient client) { Console.WriteLine("running large_unary"); var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseSize = 314159, Payload = CreateZerosPayload(271828) }; var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); Assert.AreEqual(314159, response.Payload.Body.Length); Console.WriteLine("Passed!"); } public static async Task RunClientStreamingAsync(TestService.ITestServiceClient client) { Console.WriteLine("running client_streaming"); var bodySizes = new List { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); using (var call = client.StreamingInputCall()) { await call.RequestStream.WriteAllAsync(bodySizes); var response = await call.ResponseAsync; Assert.AreEqual(74922, response.AggregatedPayloadSize); } Console.WriteLine("Passed!"); } public static async Task RunServerStreamingAsync(TestService.ITestServiceClient client) { Console.WriteLine("running server_streaming"); var bodySizes = new List { 31415, 9, 2653, 58979 }; var request = new StreamingOutputCallRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) } }; using (var call = client.StreamingOutputCall(request)) { var responseList = await call.ResponseStream.ToListAsync(); foreach (var res in responseList) { Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); } CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length)); } Console.WriteLine("Passed!"); } public static async Task RunPingPongAsync(TestService.ITestServiceClient client) { Console.WriteLine("running ping_pong"); using (var call = client.FullDuplexCall()) { await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseParameters = { new ResponseParameters { Size = 31415 } }, Payload = CreateZerosPayload(27182) }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseParameters = { new ResponseParameters { Size = 9 } }, Payload = CreateZerosPayload(8) }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseParameters = { new ResponseParameters { Size = 2653 } }, Payload = CreateZerosPayload(1828) }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseParameters = { new ResponseParameters { Size = 58979 } }, Payload = CreateZerosPayload(45904) }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); await call.RequestStream.CompleteAsync(); Assert.IsFalse(await call.ResponseStream.MoveNext()); } Console.WriteLine("Passed!"); } public static async Task RunEmptyStreamAsync(TestService.ITestServiceClient client) { Console.WriteLine("running empty_stream"); using (var call = client.FullDuplexCall()) { await call.RequestStream.CompleteAsync(); var responseList = await call.ResponseStream.ToListAsync(); Assert.AreEqual(0, responseList.Count); } Console.WriteLine("Passed!"); } public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running compute_engine_creds"); var credential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsFalse(credential.IsCreateScopedRequired); client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseSize = 314159, Payload = CreateZerosPayload(271828), FillUsername = true, FillOauthScope = true }; var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); Assert.AreEqual(314159, response.Payload.Body.Length); Assert.False(string.IsNullOrEmpty(response.OauthScope)); Assert.True(oauthScope.Contains(response.OauthScope)); Assert.AreEqual(defaultServiceAccount, response.Username); Console.WriteLine("Passed!"); } public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount) { Console.WriteLine("running jwt_token_creds"); var credential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsTrue(credential.IsCreateScopedRequired); client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseSize = 314159, Payload = CreateZerosPayload(271828), FillUsername = true, }; var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); Assert.AreEqual(314159, response.Payload.Body.Length); Assert.AreEqual(defaultServiceAccount, response.Username); Console.WriteLine("Passed!"); } public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running oauth2_auth_token"); ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); string oauth2Token = await credential.GetAccessTokenForRequestAsync(); client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); var request = new SimpleRequest { FillUsername = true, FillOauthScope = true }; var response = client.UnaryCall(request); Assert.False(string.IsNullOrEmpty(response.OauthScope)); Assert.True(oauthScope.Contains(response.OauthScope)); Assert.AreEqual(defaultServiceAccount, response.Username); Console.WriteLine("Passed!"); } public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running per_rpc_creds"); ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); string accessToken = await credential.GetAccessTokenForRequestAsync(); var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken); var request = new SimpleRequest { FillUsername = true, }; var headers = new Metadata(); headerInterceptor(null, "", headers); var response = client.UnaryCall(request, headers: headers); Assert.AreEqual(defaultServiceAccount, response.Username); Console.WriteLine("Passed!"); } public static async Task RunCancelAfterBeginAsync(TestService.ITestServiceClient client) { Console.WriteLine("running cancel_after_begin"); var cts = new CancellationTokenSource(); using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) { // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. await Task.Delay(1000); cts.Cancel(); var ex = Assert.Throws(async () => await call.ResponseAsync); Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); } Console.WriteLine("Passed!"); } public static async Task RunCancelAfterFirstResponseAsync(TestService.ITestServiceClient client) { Console.WriteLine("running cancel_after_first_response"); var cts = new CancellationTokenSource(); using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) { await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { ResponseType = PayloadType.COMPRESSABLE, ResponseParameters = { new ResponseParameters { Size = 31415 } }, Payload = CreateZerosPayload(27182) }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); cts.Cancel(); var ex = Assert.Throws(async () => await call.ResponseStream.MoveNext()); Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); } Console.WriteLine("Passed!"); } public static async Task RunTimeoutOnSleepingServerAsync(TestService.ITestServiceClient client) { Console.WriteLine("running timeout_on_sleeping_server"); var deadline = DateTime.UtcNow.AddMilliseconds(1); using (var call = client.FullDuplexCall(deadline: deadline)) { try { await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) }); } catch (InvalidOperationException) { // Deadline was reached before write has started. Eat the exception and continue. } var ex = Assert.Throws(async () => await call.ResponseStream.MoveNext()); Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCode); } Console.WriteLine("Passed!"); } // This is not an official interop test, but it's useful. public static void RunBenchmarkEmptyUnary(TestService.ITestServiceClient client) { BenchmarkUtil.RunBenchmark(10000, 10000, () => { client.EmptyCall(new Empty()); }); } private static Payload CreateZerosPayload(int size) { return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs0000644000175000017500000001031112600663151025106 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Google.Protobuf; using Grpc.Core; using Grpc.Core.Utils; namespace Grpc.Testing { /// /// Implementation of TestService server /// public class TestServiceImpl : TestService.ITestService { public Task EmptyCall(Empty request, ServerCallContext context) { return Task.FromResult(new Empty()); } public Task UnaryCall(SimpleRequest request, ServerCallContext context) { var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) }; return Task.FromResult(response); } public async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter responseStream, ServerCallContext context) { foreach (var responseParam in request.ResponseParameters) { var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) }; await responseStream.WriteAsync(response); } } public async Task StreamingInputCall(IAsyncStreamReader requestStream, ServerCallContext context) { int sum = 0; await requestStream.ForEachAsync(async request => { sum += request.Payload.Body.Length; }); return new StreamingInputCallResponse { AggregatedPayloadSize = sum }; } public async Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { await requestStream.ForEachAsync(async request => { foreach (var responseParam in request.ResponseParameters) { var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) }; await responseStream.WriteAsync(response); } }); } public async Task HalfDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { throw new NotImplementedException(); } private static Payload CreateZerosPayload(int size) { return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; } } } grpc-0.11.1/src/csharp/Grpc.Auth/0000755000175000017500000000000012600663151016561 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Auth/Grpc.Auth.csproj0000644000175000017500000001225512600663151021603 0ustar apollockapollock Debug AnyCPU {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA} Library Grpc.Auth Grpc.Auth v4.5 bin\$(Configuration)\Grpc.Auth.Xml 4f8487a9 true full false bin\Debug DEBUG; prompt 4 false pdbonly true bin\Release prompt 4 false pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. grpc-0.11.1/src/csharp/Grpc.Auth/AuthInterceptors.cs0000644000175000017500000000736712600663151022430 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; using Google.Apis.Auth.OAuth2; using Grpc.Core; using Grpc.Core.Utils; namespace Grpc.Auth { /// /// Factory methods to create authorization interceptors. Interceptors created can be registered with gRPC client classes (autogenerated client stubs that /// inherit from ). /// public static class AuthInterceptors { private const string AuthorizationHeader = "Authorization"; private const string Schema = "Bearer"; /// /// Creates interceptor that will obtain access token from any credential type that implements /// ITokenAccess. (e.g. GoogleCredential). /// /// The credential to use to obtain access tokens. /// The header interceptor. public static HeaderInterceptor FromCredential(ITokenAccess credential) { return new HeaderInterceptor((method, authUri, metadata) => { // TODO(jtattermusch): Rethink synchronous wait to obtain the result. var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None) .ConfigureAwait(false).GetAwaiter().GetResult(); metadata.Add(CreateBearerTokenHeader(accessToken)); }); } /// /// Creates OAuth2 interceptor that will use given access token as authorization. /// /// OAuth2 access token. /// The header interceptor. public static HeaderInterceptor FromAccessToken(string accessToken) { Preconditions.CheckNotNull(accessToken); return new HeaderInterceptor((method, authUri, metadata) => { metadata.Add(CreateBearerTokenHeader(accessToken)); }); } private static Metadata.Entry CreateBearerTokenHeader(string accessToken) { return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken); } } } grpc-0.11.1/src/csharp/Grpc.Auth/packages.config0000644000175000017500000000124512600663151021530 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Auth/app.config0000644000175000017500000000162112600663151020530 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Auth/Properties/0000755000175000017500000000000012600663151020715 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs0000644000175000017500000000056712600663151023647 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Auth")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.Auth/.gitignore0000644000175000017500000000002012600663151020541 0ustar apollockapollockbin obj *.nupkg grpc-0.11.1/src/csharp/Grpc.Auth/Grpc.Auth.nuspec0000644000175000017500000000235112600663151021574 0ustar apollockapollock Grpc.Auth gRPC C# Auth Auth library for C# implementation of gRPC - an RPC library and framework Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info. $version$ Google Inc. grpc-packages https://github.com/grpc/grpc/blob/master/LICENSE https://github.com/grpc/grpc false Release $version$ of gRPC C# Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 Auth OAuth2 grpc-0.11.1/src/csharp/.nuget/0000755000175000017500000000000012600663151016166 5ustar apollockapollockgrpc-0.11.1/src/csharp/.nuget/packages.config0000644000175000017500000000016112600663151021131 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Core/0000755000175000017500000000000012600663151016550 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core/IServerStreamWriter.cs0000644000175000017500000000377112600663151023037 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Grpc.Core { /// /// A writable stream of messages that is used in server-side handlers. /// public interface IServerStreamWriter : IAsyncStreamWriter { // TODO(jtattermusch): consider just using IAsyncStreamWriter instead of this interface. } } grpc-0.11.1/src/csharp/Grpc.Core/CallInvocationDetails.cs0000644000175000017500000001471212600663151023317 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Details about a client-side call to be invoked. /// /// Request message type for the call. /// Response message type for the call. public struct CallInvocationDetails { readonly Channel channel; readonly string method; readonly string host; readonly Marshaller requestMarshaller; readonly Marshaller responseMarshaller; CallOptions options; /// /// Initializes a new instance of the struct. /// /// Channel to use for this call. /// Method to call. /// Call options. public CallInvocationDetails(Channel channel, Method method, CallOptions options) : this(channel, method, null, options) { } /// /// Initializes a new instance of the struct. /// /// Channel to use for this call. /// Method to call. /// Host that contains the method. if null, default host will be used. /// Call options. public CallInvocationDetails(Channel channel, Method method, string host, CallOptions options) : this(channel, method.FullName, host, method.RequestMarshaller, method.ResponseMarshaller, options) { } /// /// Initializes a new instance of the struct. /// /// Channel to use for this call. /// Qualified method name. /// Host that contains the method. /// Request marshaller. /// Response marshaller. /// Call options. public CallInvocationDetails(Channel channel, string method, string host, Marshaller requestMarshaller, Marshaller responseMarshaller, CallOptions options) { this.channel = Preconditions.CheckNotNull(channel, "channel"); this.method = Preconditions.CheckNotNull(method, "method"); this.host = host; this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller"); this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller"); this.options = options; } /// /// Get channel associated with this call. /// public Channel Channel { get { return this.channel; } } /// /// Gets name of method to be called. /// public string Method { get { return this.method; } } /// /// Get name of host. /// public string Host { get { return this.host; } } /// /// Gets marshaller used to serialize requests. /// public Marshaller RequestMarshaller { get { return this.requestMarshaller; } } /// /// Gets marshaller used to deserialized responses. /// public Marshaller ResponseMarshaller { get { return this.responseMarshaller; } } /// /// Gets the call options. /// public CallOptions Options { get { return options; } } /// /// Returns new instance of with /// Options set to the value provided. Values of all other fields are preserved. /// public CallInvocationDetails WithOptions(CallOptions options) { var newDetails = this; newDetails.options = options; return newDetails; } } } grpc-0.11.1/src/csharp/Grpc.Core/Grpc.Core.nuspec0000644000175000017500000000245012600663151021552 0ustar apollockapollock Grpc.Core gRPC C# Core Core C# implementation of gRPC - an RPC library and framework Core C# implementation of gRPC - an RPC library and framework. See project site for more info. $version$ Google Inc. grpc-packages https://github.com/grpc/grpc/blob/master/LICENSE https://github.com/grpc/grpc false Release $version$ of gRPC C# Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 grpc-0.11.1/src/csharp/Grpc.Core/IAsyncStreamReader.cs0000644000175000017500000000401312600663151022562 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Grpc.Core { /// /// A stream of messages to be read. /// /// The message type. public interface IAsyncStreamReader : IAsyncEnumerator { // TODO(jtattermusch): consider just using IAsyncEnumerator instead of this interface. } } grpc-0.11.1/src/csharp/Grpc.Core/Utils/0000755000175000017500000000000012600663151017650 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs0000644000175000017500000000733112600663151024514 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading.Tasks; namespace Grpc.Core.Utils { /// /// Extension methods that simplify work with gRPC streaming calls. /// public static class AsyncStreamExtensions { /// /// Reads the entire stream and executes an async action for each element. /// public static async Task ForEachAsync(this IAsyncStreamReader streamReader, Func asyncAction) where T : class { while (await streamReader.MoveNext()) { await asyncAction(streamReader.Current); } } /// /// Reads the entire stream and creates a list containing all the elements read. /// public static async Task> ToListAsync(this IAsyncStreamReader streamReader) where T : class { var result = new List(); while (await streamReader.MoveNext()) { result.Add(streamReader.Current); } return result; } /// /// Writes all elements from given enumerable to the stream. /// Completes the stream afterwards unless close = false. /// public static async Task WriteAllAsync(this IClientStreamWriter streamWriter, IEnumerable elements, bool complete = true) where T : class { foreach (var element in elements) { await streamWriter.WriteAsync(element); } if (complete) { await streamWriter.CompleteAsync(); } } /// /// Writes all elements from given enumerable to the stream. /// public static async Task WriteAllAsync(this IServerStreamWriter streamWriter, IEnumerable elements) where T : class { foreach (var element in elements) { await streamWriter.WriteAsync(element); } } } } grpc-0.11.1/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs0000644000175000017500000000550012600663151022727 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; namespace Grpc.Core.Utils { /// /// Utility methods to run microbenchmarks. /// public static class BenchmarkUtil { /// /// Runs a simple benchmark preceded by warmup phase. /// public static void RunBenchmark(int warmupIterations, int benchmarkIterations, Action action) { var logger = GrpcEnvironment.Logger; logger.Info("Warmup iterations: {0}", warmupIterations); for (int i = 0; i < warmupIterations; i++) { action(); } logger.Info("Benchmark iterations: {0}", benchmarkIterations); var stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < benchmarkIterations; i++) { action(); } stopwatch.Stop(); logger.Info("Elapsed time: {0}ms", stopwatch.ElapsedMilliseconds); logger.Info("Ops per second: {0}", (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds)); } } } grpc-0.11.1/src/csharp/Grpc.Core/Utils/Preconditions.cs0000644000175000017500000001045512600663151023024 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.Core.Utils { /// /// Utility methods to simplify checking preconditions in the code. /// public static class Preconditions { /// /// Throws if condition is false. /// /// The condition. public static void CheckArgument(bool condition) { if (!condition) { throw new ArgumentException(); } } /// /// Throws with given message if condition is false. /// /// The condition. /// The error message. public static void CheckArgument(bool condition, string errorMessage) { if (!condition) { throw new ArgumentException(errorMessage); } } /// /// Throws if reference is null. /// /// The reference. public static T CheckNotNull(T reference) { if (reference == null) { throw new ArgumentNullException(); } return reference; } /// /// Throws if reference is null. /// /// The reference. /// The parameter name. public static T CheckNotNull(T reference, string paramName) { if (reference == null) { throw new ArgumentNullException(paramName); } return reference; } /// /// Throws if condition is false. /// /// The condition. public static void CheckState(bool condition) { if (!condition) { throw new InvalidOperationException(); } } /// /// Throws with given message if condition is false. /// /// The condition. /// The error message. public static void CheckState(bool condition, string errorMessage) { if (!condition) { throw new InvalidOperationException(errorMessage); } } } } grpc-0.11.1/src/csharp/Grpc.Core/ServerCallContext.cs0000644000175000017500000001531612600663151022514 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; namespace Grpc.Core { /// /// Context for a server-side call. /// public class ServerCallContext { private readonly CallSafeHandle callHandle; private readonly string method; private readonly string host; private readonly string peer; private readonly DateTime deadline; private readonly Metadata requestHeaders; private readonly CancellationToken cancellationToken; private readonly Metadata responseTrailers = new Metadata(); private Status status = Status.DefaultSuccess; private Func writeHeadersFunc; private IHasWriteOptions writeOptionsHolder; internal ServerCallContext(CallSafeHandle callHandle, string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, Func writeHeadersFunc, IHasWriteOptions writeOptionsHolder) { this.callHandle = callHandle; this.method = method; this.host = host; this.peer = peer; this.deadline = deadline; this.requestHeaders = requestHeaders; this.cancellationToken = cancellationToken; this.writeHeadersFunc = writeHeadersFunc; this.writeOptionsHolder = writeOptionsHolder; } /// /// Asynchronously sends response headers for the current call to the client. This method may only be invoked once for each call and needs to be invoked /// before any response messages are written. Writing the first response message implicitly sends empty response headers if WriteResponseHeadersAsync haven't /// been called yet. /// /// The response headers to send. /// The task that finished once response headers have been written. public Task WriteResponseHeadersAsync(Metadata responseHeaders) { return writeHeadersFunc(responseHeaders); } /// /// Creates a propagation token to be used to propagate call context to a child call. /// public ContextPropagationToken CreatePropagationToken(ContextPropagationOptions options = null) { return new ContextPropagationToken(callHandle, deadline, cancellationToken, options); } /// Name of method called in this RPC. public string Method { get { return this.method; } } /// Name of host called in this RPC. public string Host { get { return this.host; } } /// Address of the remote endpoint in URI format. public string Peer { get { return this.peer; } } /// Deadline for this RPC. public DateTime Deadline { get { return this.deadline; } } /// Initial metadata sent by client. public Metadata RequestHeaders { get { return this.requestHeaders; } } /// Cancellation token signals when call is cancelled. public CancellationToken CancellationToken { get { return this.cancellationToken; } } /// Trailers to send back to client after RPC finishes. public Metadata ResponseTrailers { get { return this.responseTrailers; } } /// Status to send back to client after RPC finishes. public Status Status { get { return this.status; } set { status = value; } } /// /// Allows setting write options for the following write. /// For streaming response calls, this property is also exposed as on IServerStreamWriter for convenience. /// Both properties are backed by the same underlying value. /// public WriteOptions WriteOptions { get { return writeOptionsHolder.WriteOptions; } set { writeOptionsHolder.WriteOptions = value; } } } /// /// Allows sharing write options between ServerCallContext and other objects. /// public interface IHasWriteOptions { /// /// Gets or sets the write options. /// WriteOptions WriteOptions { get; set; } } } grpc-0.11.1/src/csharp/Grpc.Core/GrpcEnvironment.cs0000644000175000017500000001500312600663151022216 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Encapsulates initialization and shutdown of gRPC library. /// public class GrpcEnvironment { const int THREAD_POOL_SIZE = 4; [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_init(); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_shutdown(); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_version_string(); // returns not-owned const char* static object staticLock = new object(); static GrpcEnvironment instance; static int refCount; static ILogger logger = new ConsoleLogger(); readonly GrpcThreadPool threadPool; readonly CompletionRegistry completionRegistry; readonly DebugStats debugStats = new DebugStats(); bool isClosed; /// /// Returns a reference-counted instance of initialized gRPC environment. /// Subsequent invocations return the same instance unless reference count has dropped to zero previously. /// internal static GrpcEnvironment AddRef() { lock (staticLock) { refCount++; if (instance == null) { instance = new GrpcEnvironment(); } return instance; } } /// /// Decrements the reference count for currently active environment and shuts down the gRPC environment if reference count drops to zero. /// (and blocks until the environment has been fully shutdown). /// internal static void Release() { lock (staticLock) { Preconditions.CheckState(refCount > 0); refCount--; if (refCount == 0) { instance.Close(); instance = null; } } } internal static int GetRefCount() { lock (staticLock) { return refCount; } } /// /// Gets application-wide logger used by gRPC. /// /// The logger. public static ILogger Logger { get { return logger; } } /// /// Sets the application-wide logger that should be used by gRPC. /// public static void SetLogger(ILogger customLogger) { Preconditions.CheckNotNull(customLogger, "customLogger"); logger = customLogger; } /// /// Creates gRPC environment. /// private GrpcEnvironment() { NativeLogRedirector.Redirect(); GrpcNativeInit(); completionRegistry = new CompletionRegistry(this); threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE); threadPool.Start(); } /// /// Gets the completion registry used by this gRPC environment. /// internal CompletionRegistry CompletionRegistry { get { return this.completionRegistry; } } /// /// Gets the completion queue used by this gRPC environment. /// internal CompletionQueueSafeHandle CompletionQueue { get { return this.threadPool.CompletionQueue; } } /// /// Gets the completion queue used by this gRPC environment. /// internal DebugStats DebugStats { get { return this.debugStats; } } /// /// Gets version of gRPC C core. /// internal static string GetCoreVersionString() { var ptr = grpcsharp_version_string(); // the pointer is not owned return Marshal.PtrToStringAnsi(ptr); } internal static void GrpcNativeInit() { grpcsharp_init(); } internal static void GrpcNativeShutdown() { grpcsharp_shutdown(); } /// /// Shuts down this environment. /// private void Close() { if (isClosed) { throw new InvalidOperationException("Close has already been called"); } threadPool.Stop(); GrpcNativeShutdown(); isClosed = true; debugStats.CheckOK(); } } } grpc-0.11.1/src/csharp/Grpc.Core/Version.cs0000644000175000017500000000331512600663151020526 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System.Reflection; // The current version of gRPC C#. [assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")] grpc-0.11.1/src/csharp/Grpc.Core/ServerServiceDefinition.cs0000644000175000017500000001652712600663151023712 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Collections.ObjectModel; using Grpc.Core.Internal; namespace Grpc.Core { /// /// Mapping of method names to server call handlers. /// Normally, the ServerServiceDefinition objects will be created by the BindService factory method /// that is part of the autogenerated code for a protocol buffers service definition. /// public class ServerServiceDefinition { readonly ReadOnlyDictionary callHandlers; private ServerServiceDefinition(Dictionary callHandlers) { this.callHandlers = new ReadOnlyDictionary(callHandlers); } internal IDictionary CallHandlers { get { return this.callHandlers; } } /// /// Creates a new builder object for ServerServiceDefinition. /// /// The service name. /// The builder object. public static Builder CreateBuilder(string serviceName) { return new Builder(serviceName); } /// /// Builder class for . /// public class Builder { readonly string serviceName; readonly Dictionary callHandlers = new Dictionary(); /// /// Creates a new instance of builder. /// /// The service name. public Builder(string serviceName) { this.serviceName = serviceName; } /// /// Adds a definitions for a single request - single response method. /// /// The request message class. /// The response message class. /// The method. /// The method handler. /// This builder instance. public Builder AddMethod( Method method, UnaryServerMethod handler) where TRequest : class where TResponse : class { callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler)); return this; } /// /// Adds a definitions for a client streaming method. /// /// The request message class. /// The response message class. /// The method. /// The method handler. /// This builder instance. public Builder AddMethod( Method method, ClientStreamingServerMethod handler) where TRequest : class where TResponse : class { callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler)); return this; } /// /// Adds a definitions for a server streaming method. /// /// The request message class. /// The response message class. /// The method. /// The method handler. /// This builder instance. public Builder AddMethod( Method method, ServerStreamingServerMethod handler) where TRequest : class where TResponse : class { callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler)); return this; } /// /// Adds a definitions for a bidirectional streaming method. /// /// The request message class. /// The response message class. /// The method. /// The method handler. /// This builder instance. public Builder AddMethod( Method method, DuplexStreamingServerMethod handler) where TRequest : class where TResponse : class { callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler)); return this; } /// /// Creates an immutable ServerServiceDefinition from this builder. /// /// The ServerServiceDefinition object. public ServerServiceDefinition Build() { return new ServerServiceDefinition(callHandlers); } } } } grpc-0.11.1/src/csharp/Grpc.Core/ServerPort.cs0000644000175000017500000001004612600663151021213 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core.Utils; namespace Grpc.Core { /// /// A port exposed by a server. /// public class ServerPort { /// /// Pass this value as port to have the server choose an unused listening port for you. /// Ports added to a server will contain the bound port in their property. /// public const int PickUnused = 0; readonly string host; readonly int port; readonly ServerCredentials credentials; readonly int boundPort; /// /// Creates a new port on which server should listen. /// /// The port on which server will be listening. /// the host /// the port. If zero, an unused port is chosen automatically. /// credentials to use to secure this port. public ServerPort(string host, int port, ServerCredentials credentials) { this.host = Preconditions.CheckNotNull(host, "host"); this.port = port; this.credentials = Preconditions.CheckNotNull(credentials, "credentials"); } /// /// Creates a port from an existing ServerPort instance and boundPort value. /// internal ServerPort(ServerPort serverPort, int boundPort) { this.host = serverPort.host; this.port = serverPort.port; this.credentials = serverPort.credentials; this.boundPort = boundPort; } /// The host. public string Host { get { return host; } } /// The port. public int Port { get { return port; } } /// The server credentials. public ServerCredentials Credentials { get { return credentials; } } /// /// The port actually bound by the server. This is useful if you let server /// pick port automatically. /// public int BoundPort { get { return boundPort; } } } } grpc-0.11.1/src/csharp/Grpc.Core/ContextPropagationToken.cs0000644000175000017500000001413012600663151023727 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Token for propagating context of server side handlers to child calls. /// In situations when a backend is making calls to another backend, /// it makes sense to propagate properties like deadline and cancellation /// token of the server call to the child call. /// The gRPC native layer provides some other contexts (like tracing context) that /// are not accessible to explicitly C# layer, but this token still allows propagating them. /// public class ContextPropagationToken { /// /// Default propagation mask used by C core. /// private const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff; /// /// Default propagation mask used by C# - we want to propagate deadline /// and cancellation token by our own means. /// internal const ContextPropagationFlags DefaultMask = DefaultCoreMask & ~ContextPropagationFlags.Deadline & ~ContextPropagationFlags.Cancellation; readonly CallSafeHandle parentCall; readonly DateTime deadline; readonly CancellationToken cancellationToken; readonly ContextPropagationOptions options; internal ContextPropagationToken(CallSafeHandle parentCall, DateTime deadline, CancellationToken cancellationToken, ContextPropagationOptions options) { this.parentCall = Preconditions.CheckNotNull(parentCall); this.deadline = deadline; this.cancellationToken = cancellationToken; this.options = options ?? ContextPropagationOptions.Default; } /// /// Gets the native handle of the parent call. /// internal CallSafeHandle ParentCall { get { return this.parentCall; } } /// /// Gets the parent call's deadline. /// internal DateTime ParentDeadline { get { return this.deadline; } } /// /// Gets the parent call's cancellation token. /// internal CancellationToken ParentCancellationToken { get { return this.cancellationToken; } } /// /// Get the context propagation options. /// internal ContextPropagationOptions Options { get { return this.options; } } } /// /// Options for . /// public class ContextPropagationOptions { /// /// The context propagation options that will be used by default. /// public static readonly ContextPropagationOptions Default = new ContextPropagationOptions(); bool propagateDeadline; bool propagateCancellation; /// /// Creates new context propagation options. /// /// If set to true parent call's deadline will be propagated to the child call. /// If set to true parent call's cancellation token will be propagated to the child call. public ContextPropagationOptions(bool propagateDeadline = true, bool propagateCancellation = true) { this.propagateDeadline = propagateDeadline; this.propagateCancellation = propagateCancellation; } /// true if parent call's deadline should be propagated to the child call. public bool IsPropagateDeadline { get { return this.propagateDeadline; } } /// true if parent call's cancellation token should be propagated to the child call. public bool IsPropagateCancellation { get { return this.propagateCancellation; } } } /// /// Context propagation flags from grpc/grpc.h. /// [Flags] internal enum ContextPropagationFlags { Deadline = 1, CensusStatsContext = 2, CensusTracingContext = 4, Cancellation = 8 } } grpc-0.11.1/src/csharp/Grpc.Core/Status.cs0000644000175000017500000000666612600663151020400 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using Grpc.Core.Utils; namespace Grpc.Core { /// /// Represents RPC result, which consists of and an optional detail string. /// public struct Status { /// /// Default result of a successful RPC. StatusCode=OK, empty details message. /// public static readonly Status DefaultSuccess = new Status(StatusCode.OK, ""); /// /// Default result of a cancelled RPC. StatusCode=Cancelled, empty details message. /// public static readonly Status DefaultCancelled = new Status(StatusCode.Cancelled, ""); readonly StatusCode statusCode; readonly string detail; /// /// Creates a new instance of Status. /// /// Status code. /// Detail. public Status(StatusCode statusCode, string detail) { this.statusCode = statusCode; this.detail = detail; } /// /// Gets the gRPC status code. OK indicates success, all other values indicate an error. /// public StatusCode StatusCode { get { return statusCode; } } /// /// Gets the detail. /// public string Detail { get { return detail; } } /// /// Returns a that represents the current . /// public override string ToString() { return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail); } } } grpc-0.11.1/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs0000644000175000017500000001131512600663151024005 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading.Tasks; namespace Grpc.Core { /// /// Return type for bidirectional streaming calls. /// /// Request message type for this call. /// Response message type for this call. public sealed class AsyncDuplexStreamingCall : IDisposable { readonly IClientStreamWriter requestStream; readonly IAsyncStreamReader responseStream; readonly Task responseHeadersAsync; readonly Func getStatusFunc; readonly Func getTrailersFunc; readonly Action disposeAction; internal AsyncDuplexStreamingCall(IClientStreamWriter requestStream, IAsyncStreamReader responseStream, Task responseHeadersAsync, Func getStatusFunc, Func getTrailersFunc, Action disposeAction) { this.requestStream = requestStream; this.responseStream = responseStream; this.responseHeadersAsync = responseHeadersAsync; this.getStatusFunc = getStatusFunc; this.getTrailersFunc = getTrailersFunc; this.disposeAction = disposeAction; } /// /// Async stream to read streaming responses. /// public IAsyncStreamReader ResponseStream { get { return responseStream; } } /// /// Async stream to send streaming requests. /// public IClientStreamWriter RequestStream { get { return requestStream; } } /// /// Asynchronous access to response headers. /// public Task ResponseHeadersAsync { get { return this.responseHeadersAsync; } } /// /// Gets the call status if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Status GetStatus() { return getStatusFunc(); } /// /// Gets the call trailing metadata if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Metadata GetTrailers() { return getTrailersFunc(); } /// /// Provides means to cleanup after the call. /// If the call has already finished normally (request stream has been completed and response stream has been fully read), doesn't do anything. /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. /// As a result, all resources being used by the call should be released eventually. /// public void Dispose() { disposeAction.Invoke(); } } } grpc-0.11.1/src/csharp/Grpc.Core/StatusCode.cs0000644000175000017500000001312612600663151021160 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion namespace Grpc.Core { /// /// Result of a remote procedure call. /// Based on grpc_status_code from grpc/status.h /// public enum StatusCode { /// Not an error; returned on success. OK = 0, /// The operation was cancelled (typically by the caller). Cancelled = 1, /// /// Unknown error. An example of where this error may be returned is /// if a Status value received from another address space belongs to /// an error-space that is not known in this address space. Also /// errors raised by APIs that do not return enough error information /// may be converted to this error. /// Unknown = 2, /// /// Client specified an invalid argument. Note that this differs /// from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments /// that are problematic regardless of the state of the system /// (e.g., a malformed file name). /// InvalidArgument = 3, /// /// Deadline expired before operation could complete. For operations /// that change the state of the system, this error may be returned /// even if the operation has completed successfully. For example, a /// successful response from a server could have been delayed long /// enough for the deadline to expire. /// DeadlineExceeded = 4, /// Some requested entity (e.g., file or directory) was not found. NotFound = 5, /// Some entity that we attempted to create (e.g., file or directory) already exists. AlreadyExists = 6, /// /// The caller does not have permission to execute the specified /// operation. PERMISSION_DENIED must not be used for rejections /// caused by exhausting some resource (use RESOURCE_EXHAUSTED /// instead for those errors). PERMISSION_DENIED must not be /// used if the caller can not be identified (use UNAUTHENTICATED /// instead for those errors). /// PermissionDenied = 7, /// The request does not have valid authentication credentials for the operation. Unauthenticated = 16, /// /// Some resource has been exhausted, perhaps a per-user quota, or /// perhaps the entire file system is out of space. /// ResourceExhausted = 8, /// /// Operation was rejected because the system is not in a state /// required for the operation's execution. For example, directory /// to be deleted may be non-empty, an rmdir operation is applied to /// a non-directory, etc. /// FailedPrecondition = 9, /// /// The operation was aborted, typically due to a concurrency issue /// like sequencer check failures, transaction aborts, etc. /// Aborted = 10, /// /// Operation was attempted past the valid range. E.g., seeking or /// reading past end of file. /// OutOfRange = 11, /// Operation is not implemented or not supported/enabled in this service. Unimplemented = 12, /// /// Internal errors. Means some invariants expected by underlying /// system has been broken. If you see one of these errors, /// something is very broken. /// Internal = 13, /// /// The service is currently unavailable. This is a most likely a /// transient condition and may be corrected by retrying with /// a backoff. /// Unavailable = 14, /// Unrecoverable data loss or corruption. DataLoss = 15 } } grpc-0.11.1/src/csharp/Grpc.Core/Server.cs0000644000175000017500000003233212600663151020350 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core { /// /// gRPC server. A single server can server arbitrary number of services and can listen on more than one ports. /// public class Server { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); readonly AtomicCounter activeCallCounter = new AtomicCounter(); readonly ServiceDefinitionCollection serviceDefinitions; readonly ServerPortCollection ports; readonly GrpcEnvironment environment; readonly List options; readonly ServerSafeHandle handle; readonly object myLock = new object(); readonly List serviceDefinitionsList = new List(); readonly List serverPortList = new List(); readonly Dictionary callHandlers = new Dictionary(); readonly TaskCompletionSource shutdownTcs = new TaskCompletionSource(); bool startRequested; bool shutdownRequested; /// /// Create a new server. /// /// Channel options. public Server(IEnumerable options = null) { this.serviceDefinitions = new ServiceDefinitionCollection(this); this.ports = new ServerPortCollection(this); this.environment = GrpcEnvironment.AddRef(); this.options = options != null ? new List(options) : new List(); using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options)) { this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs); } } /// /// Services that will be exported by the server once started. Register a service with this /// server by adding its definition to this collection. /// public ServiceDefinitionCollection Services { get { return serviceDefinitions; } } /// /// Ports on which the server will listen once started. Register a port with this /// server by adding its definition to this collection. /// public ServerPortCollection Ports { get { return ports; } } /// /// To allow awaiting termination of the server. /// public Task ShutdownTask { get { return shutdownTcs.Task; } } /// /// Starts the server. /// public void Start() { lock (myLock) { Preconditions.CheckState(!startRequested); startRequested = true; handle.Start(); AllowOneRpc(); } } /// /// Requests server shutdown and when there are no more calls being serviced, /// cleans up used resources. The returned task finishes when shutdown procedure /// is complete. /// public async Task ShutdownAsync() { lock (myLock) { Preconditions.CheckState(startRequested); Preconditions.CheckState(!shutdownRequested); shutdownRequested = true; } handle.ShutdownAndNotify(HandleServerShutdown, environment); await shutdownTcs.Task; DisposeHandle(); await Task.Run(() => GrpcEnvironment.Release()); } /// /// Requests server shutdown while cancelling all the in-progress calls. /// The returned task finishes when shutdown procedure is complete. /// public async Task KillAsync() { lock (myLock) { Preconditions.CheckState(startRequested); Preconditions.CheckState(!shutdownRequested); shutdownRequested = true; } handle.ShutdownAndNotify(HandleServerShutdown, environment); handle.CancelAllCalls(); await shutdownTcs.Task; DisposeHandle(); } internal void AddCallReference(object call) { activeCallCounter.Increment(); bool success = false; handle.DangerousAddRef(ref success); Preconditions.CheckState(success); } internal void RemoveCallReference(object call) { handle.DangerousRelease(); activeCallCounter.Decrement(); } /// /// Adds a service definition. /// private void AddServiceDefinitionInternal(ServerServiceDefinition serviceDefinition) { lock (myLock) { Preconditions.CheckState(!startRequested); foreach (var entry in serviceDefinition.CallHandlers) { callHandlers.Add(entry.Key, entry.Value); } serviceDefinitionsList.Add(serviceDefinition); } } /// /// Adds a listening port. /// private int AddPortInternal(ServerPort serverPort) { lock (myLock) { Preconditions.CheckNotNull(serverPort.Credentials, "serverPort"); Preconditions.CheckState(!startRequested); var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port); int boundPort; using (var nativeCredentials = serverPort.Credentials.ToNativeCredentials()) { if (nativeCredentials != null) { boundPort = handle.AddSecurePort(address, nativeCredentials); } else { boundPort = handle.AddInsecurePort(address); } } var newServerPort = new ServerPort(serverPort, boundPort); this.serverPortList.Add(newServerPort); return boundPort; } } /// /// Allows one new RPC call to be received by server. /// private void AllowOneRpc() { lock (myLock) { if (!shutdownRequested) { handle.RequestCall(HandleNewServerRpc, environment); } } } private void DisposeHandle() { var activeCallCount = activeCallCounter.Count; if (activeCallCount > 0) { Logger.Warning("Server shutdown has finished but there are still {0} active calls for that server.", activeCallCount); } handle.Dispose(); } /// /// Selects corresponding handler for given call and handles the call. /// private async Task HandleCallAsync(ServerRpcNew newRpc) { try { IServerCallHandler callHandler; if (!callHandlers.TryGetValue(newRpc.Method, out callHandler)) { callHandler = NoSuchMethodCallHandler.Instance; } await callHandler.HandleCall(newRpc, environment); } catch (Exception e) { Logger.Warning(e, "Exception while handling RPC."); } } /// /// Handles the native callback. /// private void HandleNewServerRpc(bool success, BatchContextSafeHandle ctx) { if (success) { ServerRpcNew newRpc = ctx.GetServerRpcNew(this); // after server shutdown, the callback returns with null call if (!newRpc.Call.IsInvalid) { Task.Run(async () => await HandleCallAsync(newRpc)); } } AllowOneRpc(); } /// /// Handles native callback. /// private void HandleServerShutdown(bool success, BatchContextSafeHandle ctx) { shutdownTcs.SetResult(null); } /// /// Collection of service definitions. /// public class ServiceDefinitionCollection : IEnumerable { readonly Server server; internal ServiceDefinitionCollection(Server server) { this.server = server; } /// /// Adds a service definition to the server. This is how you register /// handlers for a service with the server. Only call this before Start(). /// public void Add(ServerServiceDefinition serviceDefinition) { server.AddServiceDefinitionInternal(serviceDefinition); } /// /// Gets enumerator for this collection. /// public IEnumerator GetEnumerator() { return server.serviceDefinitionsList.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return server.serviceDefinitionsList.GetEnumerator(); } } /// /// Collection of server ports. /// public class ServerPortCollection : IEnumerable { readonly Server server; internal ServerPortCollection(Server server) { this.server = server; } /// /// Adds a new port on which server should listen. /// Only call this before Start(). /// The port on which server will be listening. /// public int Add(ServerPort serverPort) { return server.AddPortInternal(serverPort); } /// /// Adds a new port on which server should listen. /// The port on which server will be listening. /// /// the host /// the port. If zero, an unused port is chosen automatically. /// credentials to use to secure this port. public int Add(string host, int port, ServerCredentials credentials) { return Add(new ServerPort(host, port, credentials)); } /// /// Gets enumerator for this collection. /// public IEnumerator GetEnumerator() { return server.serverPortList.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return server.serverPortList.GetEnumerator(); } } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/0000755000175000017500000000000012600663151020324 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs0000644000175000017500000001141412600663151025306 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace Grpc.Core.Internal { /// /// grpc_metadata_array from grpc/grpc.h /// internal class MetadataArraySafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern MetadataArraySafeHandle grpcsharp_metadata_array_create(UIntPtr capacity); [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength); [DllImport("grpc_csharp_ext.dll")] static extern UIntPtr grpcsharp_metadata_array_count(IntPtr metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_metadata_array_get_key(IntPtr metadataArray, UIntPtr index); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_metadata_array_get_value(IntPtr metadataArray, UIntPtr index); [DllImport("grpc_csharp_ext.dll")] static extern UIntPtr grpcsharp_metadata_array_get_value_length(IntPtr metadataArray, UIntPtr index); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_metadata_array_destroy_full(IntPtr array); private MetadataArraySafeHandle() { } public static MetadataArraySafeHandle Create(Metadata metadata) { // TODO(jtattermusch): we might wanna check that the metadata is readonly var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count)); for (int i = 0; i < metadata.Count; i++) { var valueBytes = metadata[i].GetSerializedValueUnsafe(); grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length)); } return metadataArray; } /// /// Reads metadata from pointer to grpc_metadata_array /// public static Metadata ReadMetadataFromPtrUnsafe(IntPtr metadataArray) { if (metadataArray == IntPtr.Zero) { return null; } ulong count = grpcsharp_metadata_array_count(metadataArray).ToUInt64(); var metadata = new Metadata(); for (ulong i = 0; i < count; i++) { var index = new UIntPtr(i); string key = Marshal.PtrToStringAnsi(grpcsharp_metadata_array_get_key(metadataArray, index)); var bytes = new byte[grpcsharp_metadata_array_get_value_length(metadataArray, index).ToUInt64()]; Marshal.Copy(grpcsharp_metadata_array_get_value(metadataArray, index), bytes, 0, bytes.Length); metadata.Add(Metadata.Entry.CreateUnsafe(key, bytes)); } return metadata; } internal IntPtr Handle { get { return handle; } } protected override bool ReleaseHandle() { grpcsharp_metadata_array_destroy_full(handle); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs0000644000175000017500000000634212600663151026217 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// grpc_server_credentials from grpc/grpc_security.h /// internal class ServerCredentialsSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, bool forceClientAuth); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_server_credentials_release(IntPtr credentials); private ServerCredentialsSafeHandle() { } public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, bool forceClientAuth) { Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length); return grpcsharp_ssl_server_credentials_create(pemRootCerts, keyCertPairCertChainArray, keyCertPairPrivateKeyArray, new UIntPtr((ulong)keyCertPairCertChainArray.Length), forceClientAuth); } protected override bool ReleaseHandle() { grpcsharp_server_credentials_release(handle); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs0000644000175000017500000001770412600663151023724 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// Manages server side native call lifecycle. /// internal class AsyncCallServer : AsyncCallBase { readonly TaskCompletionSource finishedServersideTcs = new TaskCompletionSource(); readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); readonly Server server; public AsyncCallServer(Func serializer, Func deserializer, GrpcEnvironment environment, Server server) : base(serializer, deserializer, environment) { this.server = Preconditions.CheckNotNull(server); } public void Initialize(CallSafeHandle call) { call.SetCompletionRegistry(environment.CompletionRegistry); server.AddCallReference(this); InitializeInternal(call); } /// /// Starts a server side call. /// public Task ServerSideCallAsync() { lock (myLock) { Preconditions.CheckNotNull(call); started = true; call.StartServerSide(HandleFinishedServerside); return finishedServersideTcs.Task; } } /// /// Sends a streaming response. Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// public void StartSendMessage(TResponse msg, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { StartSendMessageInternal(msg, writeFlags, completionDelegate); } /// /// Receives a streaming request. Only one pending read action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// public void StartReadMessage(AsyncCompletionDelegate completionDelegate) { StartReadMessageInternal(completionDelegate); } /// /// Initiates sending a initial metadata. /// Even though C-core allows sending metadata in parallel to sending messages, we will treat sending metadata as a send message operation /// to make things simpler. /// completionDelegate is invoked upon completion. /// public void StartSendInitialMetadata(Metadata headers, AsyncCompletionDelegate completionDelegate) { lock (myLock) { Preconditions.CheckNotNull(headers, "metadata"); Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); Preconditions.CheckState(!initialMetadataSent, "Response headers can only be sent once per call."); Preconditions.CheckState(streamingWritesCounter == 0, "Response headers can only be sent before the first write starts."); CheckSendingAllowed(); Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); using (var metadataArray = MetadataArraySafeHandle.Create(headers)) { call.StartSendInitialMetadata(HandleSendFinished, metadataArray); } this.initialMetadataSent = true; sendCompletionDelegate = completionDelegate; } } /// /// Sends call result status, also indicating server is done with streaming responses. /// Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// public void StartSendStatusFromServer(Status status, Metadata trailers, AsyncCompletionDelegate completionDelegate) { lock (myLock) { Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); using (var metadataArray = MetadataArraySafeHandle.Create(trailers)) { call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, !initialMetadataSent); } halfcloseRequested = true; readingDone = true; sendCompletionDelegate = completionDelegate; } } /// /// Gets cancellation token that gets cancelled once close completion /// is received and the cancelled flag is set. /// public CancellationToken CancellationToken { get { return cancellationTokenSource.Token; } } public string Peer { get { return call.GetPeer(); } } protected override bool IsClient { get { return false; } } protected override void CheckReadingAllowed() { base.CheckReadingAllowed(); Preconditions.CheckArgument(!cancelRequested); } protected override void OnAfterReleaseResources() { server.RemoveCallReference(this); } /// /// Handles the server side close completion. /// private void HandleFinishedServerside(bool success, bool cancelled) { lock (myLock) { finished = true; if (cancelled) { // Once we cancel, we don't have to care that much // about reads and writes. // TODO(jtattermusch): is this still necessary? Cancel(); } ReleaseResourcesIfPossible(); } // TODO(jtattermusch): handle error if (cancelled) { cancellationTokenSource.Cancel(); } finishedServersideTcs.SetResult(null); } } }grpc-0.11.1/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs0000644000175000017500000000600412600663151024646 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Grpc.Core.Internal { internal class ServerRequestStream : IAsyncStreamReader where TRequest : class where TResponse : class { readonly AsyncCallServer call; TRequest current; public ServerRequestStream(AsyncCallServer call) { this.call = call; } public TRequest Current { get { if (current == null) { throw new InvalidOperationException("No current element is available."); } return current; } } public async Task MoveNext(CancellationToken token) { if (token != CancellationToken.None) { throw new InvalidOperationException("Cancellation of individual reads is not supported."); } var taskSource = new AsyncCompletionTaskSource(); call.StartReadMessage(taskSource.CompletionDelegate); var result = await taskSource.Task; this.current = result; return result != null; } public void Dispose() { // TODO(jtattermusch): implement the semantics of stream disposal. } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs0000644000175000017500000003011112600663151023313 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// Base for handling both client side and server side calls. /// Manages native call lifecycle and provides convenience methods. /// internal abstract class AsyncCallBase { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); protected static readonly Status DeserializeResponseFailureStatus = new Status(StatusCode.Internal, "Failed to deserialize response message."); readonly Func serializer; readonly Func deserializer; protected readonly GrpcEnvironment environment; protected readonly object myLock = new object(); protected INativeCall call; protected bool disposed; protected bool started; protected bool cancelRequested; protected AsyncCompletionDelegate sendCompletionDelegate; // Completion of a pending send or sendclose if not null. protected AsyncCompletionDelegate readCompletionDelegate; // Completion of a pending send or sendclose if not null. protected bool readingDone; // True if last read (i.e. read with null payload) was already received. protected bool halfcloseRequested; // True if send close have been initiated. protected bool finished; // True if close has been received from the peer. protected bool initialMetadataSent; protected long streamingWritesCounter; // Number of streaming send operations started so far. public AsyncCallBase(Func serializer, Func deserializer, GrpcEnvironment environment) { this.serializer = Preconditions.CheckNotNull(serializer); this.deserializer = Preconditions.CheckNotNull(deserializer); this.environment = Preconditions.CheckNotNull(environment); } /// /// Requests cancelling the call. /// public void Cancel() { lock (myLock) { Preconditions.CheckState(started); cancelRequested = true; if (!disposed) { call.Cancel(); } } } /// /// Requests cancelling the call with given status. /// protected void CancelWithStatus(Status status) { lock (myLock) { cancelRequested = true; if (!disposed) { call.CancelWithStatus(status); } } } protected void InitializeInternal(INativeCall call) { lock (myLock) { this.call = call; } } /// /// Initiates sending a message. Only one send operation can be active at a time. /// completionDelegate is invoked upon completion. /// protected void StartSendMessageInternal(TWrite msg, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { byte[] payload = UnsafeSerialize(msg); lock (myLock) { Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); call.StartSendMessage(HandleSendFinished, payload, writeFlags, !initialMetadataSent); sendCompletionDelegate = completionDelegate; initialMetadataSent = true; streamingWritesCounter++; } } /// /// Initiates reading a message. Only one read operation can be active at a time. /// completionDelegate is invoked upon completion. /// protected void StartReadMessageInternal(AsyncCompletionDelegate completionDelegate) { lock (myLock) { Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckReadingAllowed(); call.StartReceiveMessage(HandleReadFinished); readCompletionDelegate = completionDelegate; } } /// /// If there are no more pending actions and no new actions can be started, releases /// the underlying native resources. /// protected bool ReleaseResourcesIfPossible() { if (!disposed && call != null) { bool noMoreSendCompletions = sendCompletionDelegate == null && (halfcloseRequested || cancelRequested || finished); if (noMoreSendCompletions && readingDone && finished) { ReleaseResources(); return true; } } return false; } protected abstract bool IsClient { get; } private void ReleaseResources() { if (call != null) { call.Dispose(); } disposed = true; OnAfterReleaseResources(); } protected virtual void OnAfterReleaseResources() { } protected void CheckSendingAllowed() { Preconditions.CheckState(started); CheckNotCancelled(); Preconditions.CheckState(!disposed); Preconditions.CheckState(!halfcloseRequested, "Already halfclosed."); Preconditions.CheckState(!finished, "Already finished."); Preconditions.CheckState(sendCompletionDelegate == null, "Only one write can be pending at a time"); } protected virtual void CheckReadingAllowed() { Preconditions.CheckState(started); Preconditions.CheckState(!disposed); Preconditions.CheckState(!readingDone, "Stream has already been closed."); Preconditions.CheckState(readCompletionDelegate == null, "Only one read can be pending at a time"); } protected void CheckNotCancelled() { if (cancelRequested) { throw new OperationCanceledException("Remote call has been cancelled."); } } protected byte[] UnsafeSerialize(TWrite msg) { return serializer(msg); } protected Exception TrySerialize(TWrite msg, out byte[] payload) { try { payload = serializer(msg); return null; } catch (Exception e) { payload = null; return e; } } protected Exception TryDeserialize(byte[] payload, out TRead msg) { try { msg = deserializer(payload); return null; } catch (Exception e) { msg = default(TRead); return e; } } protected void FireCompletion(AsyncCompletionDelegate completionDelegate, T value, Exception error) { try { completionDelegate(value, error); } catch (Exception e) { Logger.Error(e, "Exception occured while invoking completion delegate."); } } /// /// Handles send completion. /// protected void HandleSendFinished(bool success) { AsyncCompletionDelegate origCompletionDelegate = null; lock (myLock) { origCompletionDelegate = sendCompletionDelegate; sendCompletionDelegate = null; ReleaseResourcesIfPossible(); } if (!success) { FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Send failed")); } else { FireCompletion(origCompletionDelegate, null, null); } } /// /// Handles halfclose completion. /// protected void HandleHalfclosed(bool success) { AsyncCompletionDelegate origCompletionDelegate = null; lock (myLock) { origCompletionDelegate = sendCompletionDelegate; sendCompletionDelegate = null; ReleaseResourcesIfPossible(); } if (!success) { FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Halfclose failed")); } else { FireCompletion(origCompletionDelegate, null, null); } } /// /// Handles streaming read completion. /// protected void HandleReadFinished(bool success, byte[] receivedMessage) { TRead msg = default(TRead); var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null; AsyncCompletionDelegate origCompletionDelegate = null; lock (myLock) { origCompletionDelegate = readCompletionDelegate; readCompletionDelegate = null; if (receivedMessage == null) { // This was the last read. readingDone = true; } if (deserializeException != null && IsClient) { readingDone = true; CancelWithStatus(DeserializeResponseFailureStatus); } ReleaseResourcesIfPossible(); } // TODO: handle the case when success==false if (deserializeException != null && !IsClient) { FireCompletion(origCompletionDelegate, default(TRead), new IOException("Failed to deserialize request message.", deserializeException)); return; } FireCompletion(origCompletionDelegate, msg, null); } } }grpc-0.11.1/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs0000644000175000017500000002557712600663151023461 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Runtime.InteropServices; using Grpc.Core; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// grpc_call from grpc/grpc.h /// internal class CallSafeHandle : SafeHandleZeroIsInvalid, INativeCall { public static readonly CallSafeHandle NullInstance = new CallSafeHandle(); const uint GRPC_WRITE_BUFFER_HINT = 1; CompletionRegistry completionRegistry; [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags, bool sendEmptyInitialMetadata); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_call_destroy(IntPtr call); private CallSafeHandle() { } public void SetCompletionRegistry(CompletionRegistry completionRegistry) { this.completionRegistry = completionRegistry; } public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata())); grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags) .CheckOk(); } public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags) .CheckOk(); } public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata())); grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk(); } public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient())); grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags).CheckOk(); } public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient())); grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk(); } public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success)); grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata).CheckOk(); } public void StartSendCloseFromClient(SendCompletionHandler callback) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success)); grpcsharp_call_send_close_from_client(this, ctx).CheckOk(); } public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success)); grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, sendEmptyInitialMetadata).CheckOk(); } public void StartReceiveMessage(ReceivedMessageHandler callback) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedMessage())); grpcsharp_call_recv_message(this, ctx).CheckOk(); } public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedInitialMetadata())); grpcsharp_call_recv_initial_metadata(this, ctx).CheckOk(); } public void StartServerSide(ReceivedCloseOnServerHandler callback) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedCloseOnServerCancelled())); grpcsharp_call_start_serverside(this, ctx).CheckOk(); } public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success)); grpcsharp_call_send_initial_metadata(this, ctx, metadataArray).CheckOk(); } public void Cancel() { grpcsharp_call_cancel(this).CheckOk(); } public void CancelWithStatus(Status status) { grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail).CheckOk(); } public string GetPeer() { using (var cstring = grpcsharp_call_get_peer(this)) { return cstring.GetValue(); } } protected override bool ReleaseHandle() { grpcsharp_call_destroy(handle); return true; } private static uint GetFlags(bool buffered) { return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; } } }grpc-0.11.1/src/csharp/Grpc.Core/Internal/AtomicCounter.cs0000644000175000017500000000403312600663151023427 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; namespace Grpc.Core.Internal { internal class AtomicCounter { long counter = 0; public void Increment() { Interlocked.Increment(ref counter); } public void Decrement() { Interlocked.Decrement(ref counter); } public long Count { get { return counter; } } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs0000644000175000017500000003153512600663151024222 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal { internal interface IServerCallHandler { Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment); } internal class UnaryServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); readonly Method method; readonly UnaryServerMethod handler; public UnaryServerCallHandler(Method method, UnaryServerMethod handler) { this.method = method; this.handler = handler; } public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment) { var asyncCall = new AsyncCallServer( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); var requestStream = new ServerRequestStream(asyncCall); var responseStream = new ServerResponseStream(asyncCall); Status status; var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); var request = requestStream.Current; // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated. Preconditions.CheckArgument(!await requestStream.MoveNext()); var result = await handler(request, context); status = context.Status; await responseStream.WriteAsync(result); } catch (Exception e) { Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } try { await responseStream.WriteStatusAsync(status, context.ResponseTrailers); } catch (OperationCanceledException) { // Call has been already cancelled. } await finishedTask; } } internal class ServerStreamingServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); readonly Method method; readonly ServerStreamingServerMethod handler; public ServerStreamingServerCallHandler(Method method, ServerStreamingServerMethod handler) { this.method = method; this.handler = handler; } public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment) { var asyncCall = new AsyncCallServer( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); var requestStream = new ServerRequestStream(asyncCall); var responseStream = new ServerResponseStream(asyncCall); Status status; var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); var request = requestStream.Current; // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated. Preconditions.CheckArgument(!await requestStream.MoveNext()); await handler(request, responseStream, context); status = context.Status; } catch (Exception e) { Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } try { await responseStream.WriteStatusAsync(status, context.ResponseTrailers); } catch (OperationCanceledException) { // Call has been already cancelled. } await finishedTask; } } internal class ClientStreamingServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); readonly Method method; readonly ClientStreamingServerMethod handler; public ClientStreamingServerCallHandler(Method method, ClientStreamingServerMethod handler) { this.method = method; this.handler = handler; } public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment) { var asyncCall = new AsyncCallServer( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); var requestStream = new ServerRequestStream(asyncCall); var responseStream = new ServerResponseStream(asyncCall); Status status; var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { var result = await handler(requestStream, context); status = context.Status; try { await responseStream.WriteAsync(result); } catch (OperationCanceledException) { status = Status.DefaultCancelled; } } catch (Exception e) { Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } try { await responseStream.WriteStatusAsync(status, context.ResponseTrailers); } catch (OperationCanceledException) { // Call has been already cancelled. } await finishedTask; } } internal class DuplexStreamingServerCallHandler : IServerCallHandler where TRequest : class where TResponse : class { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); readonly Method method; readonly DuplexStreamingServerMethod handler; public DuplexStreamingServerCallHandler(Method method, DuplexStreamingServerMethod handler) { this.method = method; this.handler = handler; } public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment) { var asyncCall = new AsyncCallServer( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); var requestStream = new ServerRequestStream(asyncCall); var responseStream = new ServerResponseStream(asyncCall); Status status; var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken); try { await handler(requestStream, responseStream, context); status = context.Status; } catch (Exception e) { Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } try { await responseStream.WriteStatusAsync(status, context.ResponseTrailers); } catch (OperationCanceledException) { // Call has been already cancelled. } await finishedTask; } } internal class NoSuchMethodCallHandler : IServerCallHandler { public static readonly NoSuchMethodCallHandler Instance = new NoSuchMethodCallHandler(); public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment) { // We don't care about the payload type here. var asyncCall = new AsyncCallServer( (payload) => payload, (payload) => payload, environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); var responseStream = new ServerResponseStream(asyncCall); await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, "No such method."), Metadata.Empty); await finishedTask; } } internal static class HandlerUtils { public static Status StatusFromException(Exception e) { var rpcException = e as RpcException; if (rpcException != null) { // use the status thrown by handler. return rpcException.Status; } // TODO(jtattermusch): what is the right status code here? return new Status(StatusCode.Unknown, "Exception was thrown by handler."); } public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, ServerResponseStream serverResponseStream, CancellationToken cancellationToken) where TRequest : class where TResponse : class { DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); return new ServerCallContext(newRpc.Call, newRpc.Method, newRpc.Host, peer, realtimeDeadline, newRpc.RequestMetadata, cancellationToken, serverResponseStream.WriteResponseHeadersAsync, serverResponseStream); } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs0000644000175000017500000000725212600663151024523 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.InteropServices; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal { internal delegate void OpCompletionDelegate(bool success); internal delegate void BatchCompletionDelegate(bool success, BatchContextSafeHandle ctx); internal class CompletionRegistry { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); readonly GrpcEnvironment environment; readonly ConcurrentDictionary dict = new ConcurrentDictionary(); public CompletionRegistry(GrpcEnvironment environment) { this.environment = environment; } public void Register(IntPtr key, OpCompletionDelegate callback) { environment.DebugStats.PendingBatchCompletions.Increment(); Preconditions.CheckState(dict.TryAdd(key, callback)); } public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback) { OpCompletionDelegate opCallback = ((success) => HandleBatchCompletion(success, ctx, callback)); Register(ctx.Handle, opCallback); } public OpCompletionDelegate Extract(IntPtr key) { OpCompletionDelegate value; Preconditions.CheckState(dict.TryRemove(key, out value)); environment.DebugStats.PendingBatchCompletions.Decrement(); return value; } private static void HandleBatchCompletion(bool success, BatchContextSafeHandle ctx, BatchCompletionDelegate callback) { try { callback(success, ctx); } catch (Exception e) { Logger.Error(e, "Exception occured while invoking completion delegate."); } finally { if (ctx != null) { ctx.Dispose(); } } } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs0000644000175000017500000001322512600663151024141 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; namespace Grpc.Core.Internal { /// /// grpc_channel from grpc/grpc.h /// internal class ChannelSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs); [DllImport("grpc_csharp_ext.dll")] static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs); [DllImport("grpc_csharp_ext.dll")] static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); [DllImport("grpc_csharp_ext.dll")] static extern ChannelState grpcsharp_channel_check_connectivity_state(ChannelSafeHandle channel, int tryToConnect); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_channel_watch_connectivity_state(ChannelSafeHandle channel, ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern CStringSafeHandle grpcsharp_channel_get_target(ChannelSafeHandle call); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_channel_destroy(IntPtr channel); private ChannelSafeHandle() { } public static ChannelSafeHandle CreateInsecure(string target, ChannelArgsSafeHandle channelArgs) { // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. // Doing so would make object finalizer crash if we end up abandoning the handle. GrpcEnvironment.GrpcNativeInit(); return grpcsharp_insecure_channel_create(target, channelArgs); } public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs) { // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. // Doing so would make object finalizer crash if we end up abandoning the handle. GrpcEnvironment.GrpcNativeInit(); return grpcsharp_secure_channel_create(credentials, target, channelArgs); } public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) { var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline); result.SetCompletionRegistry(registry); return result; } public ChannelState CheckConnectivityState(bool tryToConnect) { return grpcsharp_channel_check_connectivity_state(this, tryToConnect ? 1 : 0); } public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, CompletionRegistry completionRegistry, BatchCompletionDelegate callback) { var ctx = BatchContextSafeHandle.Create(); completionRegistry.RegisterBatchCompletion(ctx, callback); grpcsharp_channel_watch_connectivity_state(this, lastObservedState, deadline, cq, ctx); } public string GetTarget() { using (var cstring = grpcsharp_channel_get_target(this)) { return cstring.GetValue(); } } protected override bool ReleaseHandle() { grpcsharp_channel_destroy(handle); GrpcEnvironment.GrpcNativeShutdown(); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs0000644000175000017500000000610212600663151025022 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; namespace Grpc.Core.Internal { /// /// grpc_credentials from grpc/grpc_security.h /// internal class CredentialsSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_credentials_release(IntPtr credentials); private CredentialsSafeHandle() { } public static CredentialsSafeHandle CreateNullCredentials() { var creds = new CredentialsSafeHandle(); creds.SetHandle(IntPtr.Zero); return creds; } public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair) { if (keyCertPair != null) { return grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey); } else { return grpcsharp_ssl_credentials_create(pemRootCerts, null, null); } } protected override bool ReleaseHandle() { grpcsharp_credentials_release(handle); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs0000644000175000017500000000620512600663151024767 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Grpc.Core.Internal { internal class ClientResponseStream : IAsyncStreamReader where TRequest : class where TResponse : class { readonly AsyncCall call; TResponse current; public ClientResponseStream(AsyncCall call) { this.call = call; } public TResponse Current { get { if (current == null) { throw new InvalidOperationException("No current element is available."); } return current; } } public async Task MoveNext(CancellationToken token) { if (token != CancellationToken.None) { throw new InvalidOperationException("Cancellation of individual reads is not supported."); } var taskSource = new AsyncCompletionTaskSource(); call.StartReadMessage(taskSource.CompletionDelegate); var result = await taskSource.Task; this.current = result; if (result == null) { await call.StreamingCallFinishedTask; return false; } return true; } public void Dispose() { // TODO(jtattermusch): implement the semantics of stream disposal. } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/AsyncCall.cs0000644000175000017500000003764312600663151022541 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// Manages client side native call lifecycle. /// internal class AsyncCall : AsyncCallBase { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); readonly CallInvocationDetails details; readonly INativeCall injectedNativeCall; // for testing // Completion of a pending unary response if not null. TaskCompletionSource unaryResponseTcs; // Indicates that steaming call has finished. TaskCompletionSource streamingCallFinishedTcs = new TaskCompletionSource(); // Response headers set here once received. TaskCompletionSource responseHeadersTcs = new TaskCompletionSource(); // Set after status is received. Used for both unary and streaming response calls. ClientSideStatus? finishedStatus; public AsyncCall(CallInvocationDetails callDetails) : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer, callDetails.Channel.Environment) { this.details = callDetails.WithOptions(callDetails.Options.Normalize()); this.initialMetadataSent = true; // we always send metadata at the very beginning of the call. } /// /// This constructor should only be used for testing. /// public AsyncCall(CallInvocationDetails callDetails, INativeCall injectedNativeCall) : this(callDetails) { this.injectedNativeCall = injectedNativeCall; } // TODO: this method is not Async, so it shouldn't be in AsyncCall class, but // it is reusing fair amount of code in this class, so we are leaving it here. /// /// Blocking unary request - unary response call. /// public TResponse UnaryCall(TRequest msg) { using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create()) { byte[] payload = UnsafeSerialize(msg); unaryResponseTcs = new TaskCompletionSource(); lock (myLock) { Preconditions.CheckState(!started); started = true; Initialize(cq); halfcloseRequested = true; readingDone = true; } using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { using (var ctx = BatchContextSafeHandle.Create()) { call.StartUnary(ctx, payload, metadataArray, GetWriteFlagsForCall()); var ev = cq.Pluck(ctx.Handle); bool success = (ev.success != 0); try { HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata()); } catch (Exception e) { Logger.Error(e, "Exception occured while invoking completion delegate."); } } } // Once the blocking call returns, the result should be available synchronously. // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException. return unaryResponseTcs.Task.GetAwaiter().GetResult(); } } /// /// Starts a unary request - unary response call. /// public Task UnaryCallAsync(TRequest msg) { lock (myLock) { Preconditions.CheckState(!started); started = true; Initialize(environment.CompletionQueue); halfcloseRequested = true; readingDone = true; byte[] payload = UnsafeSerialize(msg); unaryResponseTcs = new TaskCompletionSource(); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { call.StartUnary(HandleUnaryResponse, payload, metadataArray, GetWriteFlagsForCall()); } return unaryResponseTcs.Task; } } /// /// Starts a streamed request - unary response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// public Task ClientStreamingCallAsync() { lock (myLock) { Preconditions.CheckState(!started); started = true; Initialize(environment.CompletionQueue); readingDone = true; unaryResponseTcs = new TaskCompletionSource(); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { call.StartClientStreaming(HandleUnaryResponse, metadataArray); } return unaryResponseTcs.Task; } } /// /// Starts a unary request - streamed response call. /// public void StartServerStreamingCall(TRequest msg) { lock (myLock) { Preconditions.CheckState(!started); started = true; Initialize(environment.CompletionQueue); halfcloseRequested = true; byte[] payload = UnsafeSerialize(msg); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { call.StartServerStreaming(HandleFinished, payload, metadataArray, GetWriteFlagsForCall()); } call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders); } } /// /// Starts a streaming request - streaming response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// public void StartDuplexStreamingCall() { lock (myLock) { Preconditions.CheckState(!started); started = true; Initialize(environment.CompletionQueue); using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) { call.StartDuplexStreaming(HandleFinished, metadataArray); } call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders); } } /// /// Sends a streaming request. Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// public void StartSendMessage(TRequest msg, WriteFlags writeFlags, AsyncCompletionDelegate completionDelegate) { StartSendMessageInternal(msg, writeFlags, completionDelegate); } /// /// Receives a streaming response. Only one pending read action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// public void StartReadMessage(AsyncCompletionDelegate completionDelegate) { StartReadMessageInternal(completionDelegate); } /// /// Sends halfclose, indicating client is done with streaming requests. /// Only one pending send action is allowed at any given time. /// completionDelegate is called when the operation finishes. /// public void StartSendCloseFromClient(AsyncCompletionDelegate completionDelegate) { lock (myLock) { Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); CheckSendingAllowed(); call.StartSendCloseFromClient(HandleHalfclosed); halfcloseRequested = true; sendCompletionDelegate = completionDelegate; } } /// /// Get the task that completes once if streaming call finishes with ok status and throws RpcException with given status otherwise. /// public Task StreamingCallFinishedTask { get { return streamingCallFinishedTcs.Task; } } /// /// Get the task that completes once response headers are received. /// public Task ResponseHeadersAsync { get { return responseHeadersTcs.Task; } } /// /// Gets the resulting status if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Status GetStatus() { lock (myLock) { Preconditions.CheckState(finishedStatus.HasValue, "Status can only be accessed once the call has finished."); return finishedStatus.Value.Status; } } /// /// Gets the trailing metadata if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Metadata GetTrailers() { lock (myLock) { Preconditions.CheckState(finishedStatus.HasValue, "Trailers can only be accessed once the call has finished."); return finishedStatus.Value.Trailers; } } public CallInvocationDetails Details { get { return this.details; } } protected override void OnAfterReleaseResources() { details.Channel.RemoveCallReference(this); } protected override bool IsClient { get { return true; } } private void Initialize(CompletionQueueSafeHandle cq) { var call = CreateNativeCall(cq); details.Channel.AddCallReference(this); InitializeInternal(call); RegisterCancellationCallback(); } private INativeCall CreateNativeCall(CompletionQueueSafeHandle cq) { if (injectedNativeCall != null) { return injectedNativeCall; // allows injecting a mock INativeCall in tests. } var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance; return details.Channel.Handle.CreateCall(environment.CompletionRegistry, parentCall, ContextPropagationToken.DefaultMask, cq, details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value)); } // Make sure that once cancellationToken for this call is cancelled, Cancel() will be called. private void RegisterCancellationCallback() { var token = details.Options.CancellationToken; if (token.CanBeCanceled) { token.Register(() => this.Cancel()); } } /// /// Gets WriteFlags set in callDetails.Options.WriteOptions /// private WriteFlags GetWriteFlagsForCall() { var writeOptions = details.Options.WriteOptions; return writeOptions != null ? writeOptions.Flags : default(WriteFlags); } /// /// Handles receive status completion for calls with streaming response. /// private void HandleReceivedResponseHeaders(bool success, Metadata responseHeaders) { responseHeadersTcs.SetResult(responseHeaders); } /// /// Handler for unary response completion. /// private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders) { TResponse msg = default(TResponse); var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null; lock (myLock) { finished = true; if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK) { receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers); } finishedStatus = receivedStatus; ReleaseResourcesIfPossible(); } responseHeadersTcs.SetResult(responseHeaders); var status = receivedStatus.Status; if (!success || status.StatusCode != StatusCode.OK) { unaryResponseTcs.SetException(new RpcException(status)); return; } unaryResponseTcs.SetResult(msg); } /// /// Handles receive status completion for calls with streaming response. /// private void HandleFinished(bool success, ClientSideStatus receivedStatus) { lock (myLock) { finished = true; finishedStatus = receivedStatus; ReleaseResourcesIfPossible(); } var status = receivedStatus.Status; if (!success || status.StatusCode != StatusCode.OK) { streamingCallFinishedTcs.SetException(new RpcException(status)); return; } streamingCallFinishedTcs.SetResult(null); } } }grpc-0.11.1/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs0000644000175000017500000000621012600663151023761 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// If error != null, there's been an error or operation has been cancelled. /// internal delegate void AsyncCompletionDelegate(T result, Exception error); /// /// Helper for transforming AsyncCompletionDelegate into full-fledged Task. /// internal class AsyncCompletionTaskSource { readonly TaskCompletionSource tcs = new TaskCompletionSource(); readonly AsyncCompletionDelegate completionDelegate; public AsyncCompletionTaskSource() { completionDelegate = new AsyncCompletionDelegate(HandleCompletion); } public Task Task { get { return tcs.Task; } } public AsyncCompletionDelegate CompletionDelegate { get { return completionDelegate; } } private void HandleCompletion(T value, Exception error) { if (error == null) { tcs.SetResult(value); return; } if (error is OperationCanceledException) { tcs.SetCanceled(); return; } tcs.SetException(error); } } }grpc-0.11.1/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs0000644000175000017500000001061212600663151023530 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Logging; namespace Grpc.Core.Internal { /// /// Pool of threads polling on the same completion queue. /// internal class GrpcThreadPool { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); readonly GrpcEnvironment environment; readonly object myLock = new object(); readonly List threads = new List(); readonly int poolSize; CompletionQueueSafeHandle cq; public GrpcThreadPool(GrpcEnvironment environment, int poolSize) { this.environment = environment; this.poolSize = poolSize; } public void Start() { lock (myLock) { if (cq != null) { throw new InvalidOperationException("Already started."); } cq = CompletionQueueSafeHandle.Create(); for (int i = 0; i < poolSize; i++) { threads.Add(CreateAndStartThread(i)); } } } public void Stop() { lock (myLock) { cq.Shutdown(); foreach (var thread in threads) { thread.Join(); } cq.Dispose(); } } internal CompletionQueueSafeHandle CompletionQueue { get { return cq; } } private Thread CreateAndStartThread(int i) { var thread = new Thread(new ThreadStart(RunHandlerLoop)); thread.IsBackground = false; thread.Start(); thread.Name = "grpc " + i; return thread; } /// /// Body of the polling thread. /// private void RunHandlerLoop() { CompletionQueueEvent ev; do { ev = cq.Next(); if (ev.type == GRPCCompletionType.OpComplete) { bool success = (ev.success != 0); IntPtr tag = ev.tag; try { var callback = environment.CompletionRegistry.Extract(tag); callback(success); } catch (Exception e) { Logger.Error(e, "Exception occured while invoking completion delegate"); } } } while (ev.type != GRPCCompletionType.Shutdown); } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs0000644000175000017500000001006512600663151024570 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Concurrent; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading; namespace Grpc.Core.Internal { internal delegate void GprLogDelegate(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr); /// /// Logs from gRPC C core library can get lost if your application is not a console app. /// This class allows redirection of logs to gRPC logger. /// internal static class NativeLogRedirector { static object staticLock = new object(); static GprLogDelegate writeCallback; [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_redirect_log(GprLogDelegate callback); /// /// Redirects logs from native gRPC C core library to a general logger. /// public static void Redirect() { lock (staticLock) { if (writeCallback == null) { writeCallback = new GprLogDelegate(HandleWrite); grpcsharp_redirect_log(writeCallback); } } } private static void HandleWrite(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr) { try { var logger = GrpcEnvironment.Logger; string severityString = Marshal.PtrToStringAnsi(severityStringPtr); string message = string.Format("{0} {1}:{2}: {3}", threadId, Marshal.PtrToStringAnsi(fileStringPtr), line, Marshal.PtrToStringAnsi(msgPtr)); switch (severityString) { case "D": logger.Debug(message); break; case "I": logger.Info(message); break; case "E": logger.Error(message); break; default: // severity not recognized, default to error. logger.Error(message); break; } } catch (Exception e) { Console.WriteLine("Caught exception in native callback " + e); } } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs0000644000175000017500000000431112600663151024136 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace Grpc.Core.Internal { /// /// Owned char* object. /// internal class CStringSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern void gprsharp_free(IntPtr ptr); private CStringSafeHandle() { } public string GetValue() { return Marshal.PtrToStringAnsi(handle); } protected override bool ReleaseHandle() { gprsharp_free(handle); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/Enums.cs0000644000175000017500000000702412600663151021745 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// grpc_call_error from grpc/grpc.h /// internal enum GRPCCallError { /* everything went ok */ OK = 0, /* something failed, we don't know what */ Error, /* this method is not available on the server */ NotOnServer, /* this method is not available on the client */ NotOnClient, /* this method must be called before server_accept */ AlreadyAccepted, /* this method must be called before invoke */ AlreadyInvoked, /* this method must be called after invoke */ NotInvoked, /* this call is already finished (writes_done or write_status has already been called) */ AlreadyFinished, /* there is already an outstanding read/write operation on the call */ TooManyOperations, /* the flags value was illegal for this call */ InvalidFlags } internal static class CallErrorExtensions { /// /// Checks the call API invocation's result is OK. /// public static void CheckOk(this GRPCCallError callError) { Preconditions.CheckState(callError == GRPCCallError.OK, "Call error: " + callError); } } /// /// grpc_completion_type from grpc/grpc.h /// internal enum GRPCCompletionType { /* Shutting down */ Shutdown, /* No event before timeout */ Timeout, /* operation completion */ OpComplete } /// /// gpr_clock_type from grpc/support/time.h /// internal enum GPRClockType { /* Monotonic clock */ Monotonic, /* Realtime clock */ Realtime, /* Timespan - the distance between two time points */ Timespan } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs0000644000175000017500000000646412600663151024765 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace Grpc.Core.Internal { /// /// grpc_channel_args from grpc/grpc.h /// internal class ChannelArgsSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern ChannelArgsSafeHandle grpcsharp_channel_args_create(UIntPtr numArgs); [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern void grpcsharp_channel_args_set_string(ChannelArgsSafeHandle args, UIntPtr index, string key, string value); [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_channel_args_destroy(IntPtr args); private ChannelArgsSafeHandle() { } public static ChannelArgsSafeHandle CreateNull() { return new ChannelArgsSafeHandle(); } public static ChannelArgsSafeHandle Create(int size) { return grpcsharp_channel_args_create(new UIntPtr((uint)size)); } public void SetString(int index, string key, string value) { grpcsharp_channel_args_set_string(this, new UIntPtr((uint)index), key, value); } public void SetInteger(int index, string key, int value) { grpcsharp_channel_args_set_integer(this, new UIntPtr((uint)index), key, value); } protected override bool ReleaseHandle() { grpcsharp_channel_args_destroy(handle); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs0000644000175000017500000001214512600663151024037 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Runtime.InteropServices; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// grpc_server from grpc/grpc.h /// internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args); [DllImport("grpc_csharp_ext.dll")] static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr); [DllImport("grpc_csharp_ext.dll")] static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_server_start(ServerSafeHandle server); [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_server_cancel_all_calls(ServerSafeHandle server); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_server_shutdown_and_notify_callback(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_server_destroy(IntPtr server); private ServerSafeHandle() { } public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args) { // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. // Doing so would make object finalizer crash if we end up abandoning the handle. GrpcEnvironment.GrpcNativeInit(); return grpcsharp_server_create(cq, args); } public int AddInsecurePort(string addr) { return grpcsharp_server_add_insecure_http2_port(this, addr); } public int AddSecurePort(string addr, ServerCredentialsSafeHandle credentials) { return grpcsharp_server_add_secure_http2_port(this, addr, credentials); } public void Start() { grpcsharp_server_start(this); } public void ShutdownAndNotify(BatchCompletionDelegate callback, GrpcEnvironment environment) { var ctx = BatchContextSafeHandle.Create(); environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); grpcsharp_server_shutdown_and_notify_callback(this, environment.CompletionQueue, ctx); } public void RequestCall(BatchCompletionDelegate callback, GrpcEnvironment environment) { var ctx = BatchContextSafeHandle.Create(); environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback); grpcsharp_server_request_call(this, environment.CompletionQueue, ctx).CheckOk(); } protected override bool ReleaseHandle() { grpcsharp_server_destroy(handle); GrpcEnvironment.GrpcNativeShutdown(); return true; } // Only to be called after ShutdownAndNotify. public void CancelAllCalls() { grpcsharp_server_cancel_all_calls(this); } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs0000644000175000017500000002167712600663151025171 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using Grpc.Core; namespace Grpc.Core.Internal { /// /// grpcsharp_batch_context /// internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern BatchContextSafeHandle grpcsharp_batch_context_create(); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_recv_initial_metadata(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen); [DllImport("grpc_csharp_ext.dll")] static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_recv_status_on_client_details(BatchContextSafeHandle ctx); // returns const char* [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern CallSafeHandle grpcsharp_batch_context_server_rpc_new_call(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_server_rpc_new_method(BatchContextSafeHandle ctx); // returns const char* [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_server_rpc_new_host(BatchContextSafeHandle ctx); // returns const char* [DllImport("grpc_csharp_ext.dll")] static extern Timespec grpcsharp_batch_context_server_rpc_new_deadline(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern IntPtr grpcsharp_batch_context_server_rpc_new_request_metadata(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern int grpcsharp_batch_context_recv_close_on_server_cancelled(BatchContextSafeHandle ctx); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_batch_context_destroy(IntPtr ctx); private BatchContextSafeHandle() { } public static BatchContextSafeHandle Create() { return grpcsharp_batch_context_create(); } public IntPtr Handle { get { return handle; } } // Gets data of recv_initial_metadata completion. public Metadata GetReceivedInitialMetadata() { IntPtr metadataArrayPtr = grpcsharp_batch_context_recv_initial_metadata(this); return MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr); } // Gets data of recv_status_on_client completion. public ClientSideStatus GetReceivedStatusOnClient() { string details = Marshal.PtrToStringAnsi(grpcsharp_batch_context_recv_status_on_client_details(this)); var status = new Status(grpcsharp_batch_context_recv_status_on_client_status(this), details); IntPtr metadataArrayPtr = grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this); var metadata = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr); return new ClientSideStatus(status, metadata); } // Gets data of recv_message completion. public byte[] GetReceivedMessage() { IntPtr len = grpcsharp_batch_context_recv_message_length(this); if (len == new IntPtr(-1)) { return null; } byte[] data = new byte[(int)len]; grpcsharp_batch_context_recv_message_to_buffer(this, data, new UIntPtr((ulong)data.Length)); return data; } // Gets data of server_rpc_new completion. public ServerRpcNew GetServerRpcNew(Server server) { var call = grpcsharp_batch_context_server_rpc_new_call(this); var method = Marshal.PtrToStringAnsi(grpcsharp_batch_context_server_rpc_new_method(this)); var host = Marshal.PtrToStringAnsi(grpcsharp_batch_context_server_rpc_new_host(this)); var deadline = grpcsharp_batch_context_server_rpc_new_deadline(this); IntPtr metadataArrayPtr = grpcsharp_batch_context_server_rpc_new_request_metadata(this); var metadata = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr); return new ServerRpcNew(server, call, method, host, deadline, metadata); } // Gets data of receive_close_on_server completion. public bool GetReceivedCloseOnServerCancelled() { return grpcsharp_batch_context_recv_close_on_server_cancelled(this) != 0; } protected override bool ReleaseHandle() { grpcsharp_batch_context_destroy(handle); return true; } } /// /// Status + metadata received on client side when call finishes. /// (when receive_status_on_client operation finishes). /// internal struct ClientSideStatus { readonly Status status; readonly Metadata trailers; public ClientSideStatus(Status status, Metadata trailers) { this.status = status; this.trailers = trailers; } public Status Status { get { return this.status; } } public Metadata Trailers { get { return this.trailers; } } } /// /// Details of a newly received RPC. /// internal struct ServerRpcNew { readonly Server server; readonly CallSafeHandle call; readonly string method; readonly string host; readonly Timespec deadline; readonly Metadata requestMetadata; public ServerRpcNew(Server server, CallSafeHandle call, string method, string host, Timespec deadline, Metadata requestMetadata) { this.server = server; this.call = call; this.method = method; this.host = host; this.deadline = deadline; this.requestMetadata = requestMetadata; } public Server Server { get { return this.server; } } public CallSafeHandle Call { get { return this.call; } } public string Method { get { return this.method; } } public string Host { get { return this.host; } } public Timespec Deadline { get { return this.deadline; } } public Metadata RequestMetadata { get { return this.requestMetadata; } } } }grpc-0.11.1/src/csharp/Grpc.Core/Internal/Timespec.cs0000644000175000017500000002160112600663151022424 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// /// gpr_timespec from grpc/support/time.h /// [StructLayout(LayoutKind.Sequential)] internal struct Timespec { const long NanosPerSecond = 1000 * 1000 * 1000; const long NanosPerTick = 100; const long TicksPerSecond = NanosPerSecond / NanosPerTick; static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); [DllImport("grpc_csharp_ext.dll")] static extern Timespec gprsharp_now(GPRClockType clockType); [DllImport("grpc_csharp_ext.dll")] static extern Timespec gprsharp_inf_future(GPRClockType clockType); [DllImport("grpc_csharp_ext.dll")] static extern Timespec gprsharp_inf_past(GPRClockType clockType); [DllImport("grpc_csharp_ext.dll")] static extern Timespec gprsharp_convert_clock_type(Timespec t, GPRClockType targetClock); [DllImport("grpc_csharp_ext.dll")] static extern int gprsharp_sizeof_timespec(); public Timespec(IntPtr tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime) { } public Timespec(IntPtr tv_sec, int tv_nsec, GPRClockType clock_type) { this.tv_sec = tv_sec; this.tv_nsec = tv_nsec; this.clock_type = clock_type; } // NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8 // so IntPtr seems to have the right size to work on both. private System.IntPtr tv_sec; private int tv_nsec; private GPRClockType clock_type; /// /// Timespec a long time in the future. /// public static Timespec InfFuture { get { return gprsharp_inf_future(GPRClockType.Realtime); } } /// /// Timespec a long time in the past. /// public static Timespec InfPast { get { return gprsharp_inf_past(GPRClockType.Realtime); } } /// /// Return Timespec representing the current time. /// public static Timespec Now { get { return gprsharp_now(GPRClockType.Realtime); } } /// /// Seconds since unix epoch. /// public IntPtr TimevalSeconds { get { return tv_sec; } } /// /// The nanoseconds part of timeval. /// public int TimevalNanos { get { return tv_nsec; } } /// /// Converts the timespec to desired clock type. /// public Timespec ToClockType(GPRClockType targetClock) { return gprsharp_convert_clock_type(this, targetClock); } /// /// Converts Timespec to DateTime. /// Timespec needs to be of type GPRClockType.Realtime and needs to represent a legal value. /// DateTime has lower resolution (100ns), so rounding can occurs. /// Value are always rounded up to the nearest DateTime value in the future. /// /// For Timespec.InfFuture or if timespec is after the largest representable DateTime, DateTime.MaxValue is returned. /// For Timespec.InfPast or if timespec is before the lowest representable DateTime, DateTime.MinValue is returned. /// /// Unless DateTime.MaxValue or DateTime.MinValue is returned, the resulting DateTime is always in UTC /// (DateTimeKind.Utc) /// public DateTime ToDateTime() { Preconditions.CheckState(tv_nsec >= 0 && tv_nsec < NanosPerSecond); Preconditions.CheckState(clock_type == GPRClockType.Realtime); // fast path for InfFuture if (this.Equals(InfFuture)) { return DateTime.MaxValue; } // fast path for InfPast if (this.Equals(InfPast)) { return DateTime.MinValue; } try { // convert nanos to ticks, round up to the nearest tick long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % NanosPerTick != 0) ? 1 : 0); long ticksTotal = checked(tv_sec.ToInt64() * TicksPerSecond + ticksFromNanos); return UnixEpoch.AddTicks(ticksTotal); } catch (OverflowException) { // ticks out of long range return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue; } catch (ArgumentOutOfRangeException) { // resulting date time would be larger than MaxValue return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue; } } /// /// Creates DateTime to Timespec. /// DateTime has to be in UTC (DateTimeKind.Utc) unless it's DateTime.MaxValue or DateTime.MinValue. /// For DateTime.MaxValue of date time after the largest representable Timespec, Timespec.InfFuture is returned. /// For DateTime.MinValue of date time before the lowest representable Timespec, Timespec.InfPast is returned. /// /// The date time. /// Date time. public static Timespec FromDateTime(DateTime dateTime) { if (dateTime == DateTime.MaxValue) { return Timespec.InfFuture; } if (dateTime == DateTime.MinValue) { return Timespec.InfPast; } Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime needs of kind DateTimeKind.Utc or be equal to DateTime.MaxValue or DateTime.MinValue."); try { TimeSpan timeSpan = dateTime - UnixEpoch; long ticks = timeSpan.Ticks; long seconds = ticks / TicksPerSecond; int nanos = (int)((ticks % TicksPerSecond) * NanosPerTick); if (nanos < 0) { // correct the result based on C# modulo semantics for negative dividend seconds--; nanos += (int)NanosPerSecond; } // new IntPtr possibly throws OverflowException return new Timespec(new IntPtr(seconds), nanos); } catch (OverflowException) { return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast; } catch (ArgumentOutOfRangeException) { return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast; } } internal static int NativeSize { get { return gprsharp_sizeof_timespec(); } } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs0000644000175000017500000000442712600663151025317 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; namespace Grpc.Core.Internal { /// /// Safe handle to wrap native objects. /// internal abstract class SafeHandleZeroIsInvalid : SafeHandle { public SafeHandleZeroIsInvalid() : base(IntPtr.Zero, true) { } public SafeHandleZeroIsInvalid(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) { } public override bool IsInvalid { get { return handle == IntPtr.Zero; } } protected override bool ReleaseHandle() { // handle is not owned. return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/INativeCall.cs0000644000175000017500000000757612600663151023025 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.Core.Internal { internal delegate void UnaryResponseClientHandler(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders); // Received status for streaming response calls. internal delegate void ReceivedStatusOnClientHandler(bool success, ClientSideStatus receivedStatus); internal delegate void ReceivedMessageHandler(bool success, byte[] receivedMessage); internal delegate void ReceivedResponseHeadersHandler(bool success, Metadata responseHeaders); internal delegate void SendCompletionHandler(bool success); internal delegate void ReceivedCloseOnServerHandler(bool success, bool cancelled); /// /// Abstraction of a native call object. /// internal interface INativeCall : IDisposable { void Cancel(); void CancelWithStatus(Grpc.Core.Status status); string GetPeer(); void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags); void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags); void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray); void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags); void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray); void StartReceiveMessage(ReceivedMessageHandler callback); void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback); void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray); void StartSendMessage(SendCompletionHandler callback, byte[] payload, Grpc.Core.WriteFlags writeFlags, bool sendEmptyInitialMetadata); void StartSendCloseFromClient(SendCompletionHandler callback); void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata); void StartServerSide(ReceivedCloseOnServerHandler callback); } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs0000644000175000017500000000664512600663151025027 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading.Tasks; using Grpc.Core.Internal; namespace Grpc.Core.Internal { /// /// Writes responses asynchronously to an underlying AsyncCallServer object. /// internal class ServerResponseStream : IServerStreamWriter, IHasWriteOptions where TRequest : class where TResponse : class { readonly AsyncCallServer call; WriteOptions writeOptions; public ServerResponseStream(AsyncCallServer call) { this.call = call; } public Task WriteAsync(TResponse message) { var taskSource = new AsyncCompletionTaskSource(); call.StartSendMessage(message, GetWriteFlags(), taskSource.CompletionDelegate); return taskSource.Task; } public Task WriteStatusAsync(Status status, Metadata trailers) { var taskSource = new AsyncCompletionTaskSource(); call.StartSendStatusFromServer(status, trailers, taskSource.CompletionDelegate); return taskSource.Task; } public Task WriteResponseHeadersAsync(Metadata responseHeaders) { var taskSource = new AsyncCompletionTaskSource(); call.StartSendInitialMetadata(responseHeaders, taskSource.CompletionDelegate); return taskSource.Task; } public WriteOptions WriteOptions { get { return writeOptions; } set { writeOptions = value; } } private WriteFlags GetWriteFlags() { var options = writeOptions; return options != null ? options.Flags : default(WriteFlags); } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/DebugStats.cs0000644000175000017500000000451012600663151022720 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; namespace Grpc.Core.Internal { internal class DebugStats { public readonly AtomicCounter PendingBatchCompletions = new AtomicCounter(); /// /// Checks the debug stats and take action for any inconsistency found. /// public void CheckOK() { var pendingBatchCompletions = PendingBatchCompletions.Count; if (pendingBatchCompletions != 0) { DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions)); } } private void DebugWarning(string message) { throw new Exception("Shutdown check: " + message); } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/CompletionQueueEvent.cs0000644000175000017500000000424712600663151025002 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; namespace Grpc.Core.Internal { /// /// grpc_event from grpc/grpc.h /// [StructLayout(LayoutKind.Sequential)] internal struct CompletionQueueEvent { [DllImport("grpc_csharp_ext.dll")] static extern int grpcsharp_sizeof_grpc_event(); public GRPCCompletionType type; public int success; public IntPtr tag; internal static int NativeSize { get { return grpcsharp_sizeof_grpc_event(); } } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ServerCalls.cs0000644000175000017500000000617512600663151023111 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; using System.Threading.Tasks; using Grpc.Core; namespace Grpc.Core.Internal { internal static class ServerCalls { public static IServerCallHandler UnaryCall(Method method, UnaryServerMethod handler) where TRequest : class where TResponse : class { return new UnaryServerCallHandler(method, handler); } public static IServerCallHandler ClientStreamingCall(Method method, ClientStreamingServerMethod handler) where TRequest : class where TResponse : class { return new ClientStreamingServerCallHandler(method, handler); } public static IServerCallHandler ServerStreamingCall(Method method, ServerStreamingServerMethod handler) where TRequest : class where TResponse : class { return new ServerStreamingServerCallHandler(method, handler); } public static IServerCallHandler DuplexStreamingCall(Method method, DuplexStreamingServerMethod handler) where TRequest : class where TResponse : class { return new DuplexStreamingServerCallHandler(method, handler); } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs0000644000175000017500000000635412600663151025714 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace Grpc.Core.Internal { /// /// grpc_completion_queue from grpc/grpc.h /// internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create(); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_completion_queue_shutdown(CompletionQueueSafeHandle cq); [DllImport("grpc_csharp_ext.dll")] static extern CompletionQueueEvent grpcsharp_completion_queue_next(CompletionQueueSafeHandle cq); [DllImport("grpc_csharp_ext.dll")] static extern CompletionQueueEvent grpcsharp_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_completion_queue_destroy(IntPtr cq); private CompletionQueueSafeHandle() { } public static CompletionQueueSafeHandle Create() { return grpcsharp_completion_queue_create(); } public CompletionQueueEvent Next() { return grpcsharp_completion_queue_next(this); } public CompletionQueueEvent Pluck(IntPtr tag) { return grpcsharp_completion_queue_pluck(this, tag); } public void Shutdown() { grpcsharp_completion_queue_shutdown(this); } protected override bool ReleaseHandle() { grpcsharp_completion_queue_destroy(handle); return true; } } } grpc-0.11.1/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs0000644000175000017500000000605712600663151024626 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading.Tasks; using Grpc.Core.Internal; namespace Grpc.Core.Internal { /// /// Writes requests asynchronously to an underlying AsyncCall object. /// internal class ClientRequestStream : IClientStreamWriter { readonly AsyncCall call; WriteOptions writeOptions; public ClientRequestStream(AsyncCall call) { this.call = call; this.writeOptions = call.Details.Options.WriteOptions; } public Task WriteAsync(TRequest message) { var taskSource = new AsyncCompletionTaskSource(); call.StartSendMessage(message, GetWriteFlags(), taskSource.CompletionDelegate); return taskSource.Task; } public Task CompleteAsync() { var taskSource = new AsyncCompletionTaskSource(); call.StartSendCloseFromClient(taskSource.CompletionDelegate); return taskSource.Task; } public WriteOptions WriteOptions { get { return this.writeOptions; } set { writeOptions = value; } } private WriteFlags GetWriteFlags() { var options = writeOptions; return options != null ? options.Flags : default(WriteFlags); } } } grpc-0.11.1/src/csharp/Grpc.Core/IAsyncStreamWriter.cs0000644000175000017500000000467612600663151022653 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Grpc.Core { /// /// A writable stream of messages. /// /// The message type. public interface IAsyncStreamWriter { /// /// Writes a single asynchronously. Only one write can be pending at a time. /// /// the message to be written. Cannot be null. Task WriteAsync(T message); /// /// Write options that will be used for the next write. /// If null, default options will be used. /// Once set, this property maintains its value across subsequent /// writes. /// WriteOptions WriteOptions { get; set; } } } grpc-0.11.1/src/csharp/Grpc.Core/Method.cs0000644000175000017500000001473112600663151020325 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Method types supported by gRPC. /// public enum MethodType { /// Single request sent from client, single response received from server. Unary, /// Stream of request sent from client, single response received from server. ClientStreaming, /// Single request sent from client, stream of responses received from server. ServerStreaming, /// Both server and client can stream arbitrary number of requests and responses simultaneously. DuplexStreaming } /// /// A non-generic representation of a remote method. /// public interface IMethod { /// /// Gets the type of the method. /// MethodType Type { get; } /// /// Gets the name of the service to which this method belongs. /// string ServiceName { get; } /// /// Gets the unqualified name of the method. /// string Name { get; } /// /// Gets the fully qualified name of the method. On the server side, methods are dispatched /// based on this name. /// string FullName { get; } } /// /// A description of a remote method. /// /// Request message type for this method. /// Response message type for this method. public class Method : IMethod { readonly MethodType type; readonly string serviceName; readonly string name; readonly Marshaller requestMarshaller; readonly Marshaller responseMarshaller; readonly string fullName; /// /// Initializes a new instance of the Method class. /// /// Type of method. /// Name of service this method belongs to. /// Unqualified name of the method. /// Marshaller used for request messages. /// Marshaller used for response messages. public Method(MethodType type, string serviceName, string name, Marshaller requestMarshaller, Marshaller responseMarshaller) { this.type = type; this.serviceName = Preconditions.CheckNotNull(serviceName, "serviceName"); this.name = Preconditions.CheckNotNull(name, "name"); this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller"); this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller"); this.fullName = GetFullName(serviceName, name); } /// /// Gets the type of the method. /// public MethodType Type { get { return this.type; } } /// /// Gets the name of the service to which this method belongs. /// public string ServiceName { get { return this.serviceName; } } /// /// Gets the unqualified name of the method. /// public string Name { get { return this.name; } } /// /// Gets the marshaller used for request messages. /// public Marshaller RequestMarshaller { get { return this.requestMarshaller; } } /// /// Gets the marshaller used for response messages. /// public Marshaller ResponseMarshaller { get { return this.responseMarshaller; } } /// /// Gets the fully qualified name of the method. On the server side, methods are dispatched /// based on this name. /// public string FullName { get { return this.fullName; } } /// /// Gets full name of the method including the service name. /// internal static string GetFullName(string serviceName, string methodName) { return "/" + serviceName + "/" + methodName; } } } grpc-0.11.1/src/csharp/Grpc.Core/Metadata.cs0000644000175000017500000002657212600663151020633 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using Grpc.Core.Utils; namespace Grpc.Core { /// /// A collection of metadata entries that can be exchanged during a call. /// gRPC supports these types of metadata: /// /// Request headersare sent by the client at the beginning of a remote call before any request messages are sent. /// Response headersare sent by the server at the beginning of a remote call handler before any response messages are sent. /// Response trailersare sent by the server at the end of a remote call along with resulting call status. /// /// public sealed class Metadata : IList { /// /// All binary headers should have this suffix. /// public const string BinaryHeaderSuffix = "-bin"; /// /// An read-only instance of metadata containing no entries. /// public static readonly Metadata Empty = new Metadata().Freeze(); readonly List entries; bool readOnly; /// /// Initializes a new instance of Metadata. /// public Metadata() { this.entries = new List(); } /// /// Makes this object read-only. /// /// this object internal Metadata Freeze() { this.readOnly = true; return this; } // TODO: add support for access by key #region IList members public int IndexOf(Metadata.Entry item) { return entries.IndexOf(item); } public void Insert(int index, Metadata.Entry item) { CheckWriteable(); entries.Insert(index, item); } public void RemoveAt(int index) { CheckWriteable(); entries.RemoveAt(index); } public Metadata.Entry this[int index] { get { return entries[index]; } set { CheckWriteable(); entries[index] = value; } } public void Add(Metadata.Entry item) { CheckWriteable(); entries.Add(item); } public void Add(string key, string value) { Add(new Entry(key, value)); } public void Add(string key, byte[] valueBytes) { Add(new Entry(key, valueBytes)); } public void Clear() { CheckWriteable(); entries.Clear(); } public bool Contains(Metadata.Entry item) { return entries.Contains(item); } public void CopyTo(Metadata.Entry[] array, int arrayIndex) { entries.CopyTo(array, arrayIndex); } public int Count { get { return entries.Count; } } public bool IsReadOnly { get { return readOnly; } } public bool Remove(Metadata.Entry item) { CheckWriteable(); return entries.Remove(item); } public IEnumerator GetEnumerator() { return entries.GetEnumerator(); } IEnumerator System.Collections.IEnumerable.GetEnumerator() { return entries.GetEnumerator(); } private void CheckWriteable() { Preconditions.CheckState(!readOnly, "Object is read only"); } #endregion /// /// Metadata entry /// public struct Entry { private static readonly Encoding Encoding = Encoding.ASCII; private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$"); readonly string key; readonly string value; readonly byte[] valueBytes; private Entry(string key, string value, byte[] valueBytes) { this.key = key; this.value = value; this.valueBytes = valueBytes; } /// /// Initializes a new instance of the struct with a binary value. /// /// Metadata key, needs to have suffix indicating a binary valued metadata entry. /// Value bytes. public Entry(string key, byte[] valueBytes) { this.key = NormalizeKey(key); Preconditions.CheckArgument(this.key.EndsWith(BinaryHeaderSuffix), "Key for binary valued metadata entry needs to have suffix indicating binary value."); this.value = null; Preconditions.CheckNotNull(valueBytes, "valueBytes"); this.valueBytes = new byte[valueBytes.Length]; Buffer.BlockCopy(valueBytes, 0, this.valueBytes, 0, valueBytes.Length); // defensive copy to guarantee immutability } /// /// Initializes a new instance of the struct holding an ASCII value. /// /// Metadata key, must not use suffix indicating a binary valued metadata entry. /// Value string. Only ASCII characters are allowed. public Entry(string key, string value) { this.key = NormalizeKey(key); Preconditions.CheckArgument(!this.key.EndsWith(BinaryHeaderSuffix), "Key for ASCII valued metadata entry cannot have suffix indicating binary value."); this.value = Preconditions.CheckNotNull(value, "value"); this.valueBytes = null; } /// /// Gets the metadata entry key. /// public string Key { get { return this.key; } } /// /// Gets the binary value of this metadata entry. /// public byte[] ValueBytes { get { if (valueBytes == null) { return Encoding.GetBytes(value); } // defensive copy to guarantee immutability var bytes = new byte[valueBytes.Length]; Buffer.BlockCopy(valueBytes, 0, bytes, 0, valueBytes.Length); return bytes; } } /// /// Gets the string value of this metadata entry. /// public string Value { get { Preconditions.CheckState(!IsBinary, "Cannot access string value of a binary metadata entry"); return value ?? Encoding.GetString(valueBytes); } } /// /// Returns true if this entry is a binary-value entry. /// public bool IsBinary { get { return value == null; } } /// /// Returns a that represents the current . /// public override string ToString() { if (IsBinary) { return string.Format("[Entry: key={0}, valueBytes={1}]", key, valueBytes); } return string.Format("[Entry: key={0}, value={1}]", key, value); } /// /// Gets the serialized value for this entry. For binary metadata entries, this leaks /// the internal valueBytes byte array and caller must not change contents of it. /// internal byte[] GetSerializedValueUnsafe() { return valueBytes ?? Encoding.GetBytes(value); } /// /// Creates a binary value or ascii value metadata entry from data received from the native layer. /// We trust C core to give us well-formed data, so we don't perform any checks or defensive copying. /// internal static Entry CreateUnsafe(string key, byte[] valueBytes) { if (key.EndsWith(BinaryHeaderSuffix)) { return new Entry(key, null, valueBytes); } return new Entry(key, Encoding.GetString(valueBytes), null); } private static string NormalizeKey(string key) { var normalized = Preconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture); Preconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized), "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens."); return normalized; } } } } grpc-0.11.1/src/csharp/Grpc.Core/VersionInfo.cs0000644000175000017500000000356312600663151021347 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion namespace Grpc.Core { /// /// Provides info about current version of gRPC. /// public static class VersionInfo { /// /// Current version of gRPC C# /// public const string CurrentVersion = "0.7.1"; } } grpc-0.11.1/src/csharp/Grpc.Core/ClientBase.cs0000644000175000017500000001221312600663151021107 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Grpc.Core { /// /// Interceptor for call headers. /// public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata); /// /// Base class for client-side stubs. /// public abstract class ClientBase { // Regex for removal of the optional DNS scheme, trailing port, and trailing backslash static readonly Regex ChannelTargetPattern = new Regex(@"^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$"); readonly Channel channel; readonly string authUriBase; /// /// Initializes a new instance of ClientBase class. /// /// The channel to use for remote call invocation. public ClientBase(Channel channel) { this.channel = channel; this.authUriBase = GetAuthUriBase(channel.Target); } /// /// Can be used to register a custom header (request metadata) interceptor. /// The interceptor is invoked each time a new call on this client is started. /// public HeaderInterceptor HeaderInterceptor { get; set; } /// /// gRPC supports multiple "hosts" being served by a single server. /// This property can be used to set the target host explicitly. /// By default, this will be set to null with the meaning /// "use default host". /// public string Host { get; set; } /// /// Channel associated with this client. /// public Channel Channel { get { return this.channel; } } /// /// Creates a new call to given method. /// /// The method to invoke. /// The call options. /// Request message type. /// Response message type. /// The call invocation details. protected CallInvocationDetails CreateCall(Method method, CallOptions options) where TRequest : class where TResponse : class { var interceptor = HeaderInterceptor; if (interceptor != null) { if (options.Headers == null) { options = options.WithHeaders(new Metadata()); } var authUri = authUriBase != null ? authUriBase + method.ServiceName : null; interceptor(method, authUri, options.Headers); } return new CallInvocationDetails(channel, method, Host, options); } /// /// Creates Auth URI base from channel's target (the one passed at channel creation). /// Fully-qualified service name is to be appended to this. /// internal static string GetAuthUriBase(string target) { var match = ChannelTargetPattern.Match(target); if (!match.Success) { return null; } return "https://" + match.Groups[2].Value + "/"; } } } grpc-0.11.1/src/csharp/Grpc.Core/CompressionLevel.cs0000644000175000017500000000417512600663151022377 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.Core { /// /// Compression level based on grpc_compression_level from grpc/compression.h /// public enum CompressionLevel { /// /// No compression. /// None = 0, /// /// Low compression. /// Low, /// /// Medium compression. /// Medium, /// /// High compression. /// High, } } grpc-0.11.1/src/csharp/Grpc.Core/AsyncUnaryCall.cs0000644000175000017500000001060112600663151021765 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace Grpc.Core { /// /// Return type for single request - single response call. /// /// Response message type for this call. public sealed class AsyncUnaryCall : IDisposable { readonly Task responseAsync; readonly Task responseHeadersAsync; readonly Func getStatusFunc; readonly Func getTrailersFunc; readonly Action disposeAction; internal AsyncUnaryCall(Task responseAsync, Task responseHeadersAsync, Func getStatusFunc, Func getTrailersFunc, Action disposeAction) { this.responseAsync = responseAsync; this.responseHeadersAsync = responseHeadersAsync; this.getStatusFunc = getStatusFunc; this.getTrailersFunc = getTrailersFunc; this.disposeAction = disposeAction; } /// /// Asynchronous call result. /// public Task ResponseAsync { get { return this.responseAsync; } } /// /// Asynchronous access to response headers. /// public Task ResponseHeadersAsync { get { return this.responseHeadersAsync; } } /// /// Allows awaiting this object directly. /// public TaskAwaiter GetAwaiter() { return responseAsync.GetAwaiter(); } /// /// Gets the call status if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Status GetStatus() { return getStatusFunc(); } /// /// Gets the call trailing metadata if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Metadata GetTrailers() { return getTrailersFunc(); } /// /// Provides means to cleanup after the call. /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. /// As a result, all resources being used by the call should be released eventually. /// public void Dispose() { disposeAction.Invoke(); } } } grpc-0.11.1/src/csharp/Grpc.Core/Channel.cs0000644000175000017500000002305612600663151020455 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Represents a gRPC channel. Channels are an abstraction of long-lived connections to remote servers. /// More client objects can reuse the same channel. Creating a channel is an expensive operation compared to invoking /// a remote call so in general you should reuse a single channel for as many calls as possible. /// public class Channel { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); readonly object myLock = new object(); readonly AtomicCounter activeCallCounter = new AtomicCounter(); readonly string target; readonly GrpcEnvironment environment; readonly ChannelSafeHandle handle; readonly List options; bool shutdownRequested; /// /// Creates a channel that connects to a specific host. /// Port will default to 80 for an unsecure channel and to 443 for a secure channel. /// /// Target of the channel. /// Credentials to secure the channel. /// Channel options. public Channel(string target, Credentials credentials, IEnumerable options = null) { this.target = Preconditions.CheckNotNull(target, "target"); this.environment = GrpcEnvironment.AddRef(); this.options = options != null ? new List(options) : new List(); EnsureUserAgentChannelOption(this.options); using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials()) using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options)) { if (nativeCredentials != null) { this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, target, nativeChannelArgs); } else { this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs); } } } /// /// Creates a channel that connects to a specific host and port. /// /// The name or IP address of the host. /// The port. /// Credentials to secure the channel. /// Channel options. public Channel(string host, int port, Credentials credentials, IEnumerable options = null) : this(string.Format("{0}:{1}", host, port), credentials, options) { } /// /// Gets current connectivity state of this channel. /// public ChannelState State { get { return handle.CheckConnectivityState(false); } } /// /// Returned tasks completes once channel state has become different from /// given lastObservedState. /// If deadline is reached or and error occurs, returned task is cancelled. /// public Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null) { Preconditions.CheckArgument(lastObservedState != ChannelState.FatalFailure, "FatalFailure is a terminal state. No further state changes can occur."); var tcs = new TaskCompletionSource(); var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture; var handler = new BatchCompletionDelegate((success, ctx) => { if (success) { tcs.SetResult(null); } else { tcs.SetCanceled(); } }); handle.WatchConnectivityState(lastObservedState, deadlineTimespec, environment.CompletionQueue, environment.CompletionRegistry, handler); return tcs.Task; } /// Resolved address of the remote endpoint in URI format. public string ResolvedTarget { get { return handle.GetTarget(); } } /// The original target used to create the channel. public string Target { get { return this.target; } } /// /// Allows explicitly requesting channel to connect without starting an RPC. /// Returned task completes once state Ready was seen. If the deadline is reached, /// or channel enters the FatalFailure state, the task is cancelled. /// There is no need to call this explicitly unless your use case requires that. /// Starting an RPC on a new channel will request connection implicitly. /// /// The deadline. null indicates no deadline. public async Task ConnectAsync(DateTime? deadline = null) { var currentState = handle.CheckConnectivityState(true); while (currentState != ChannelState.Ready) { if (currentState == ChannelState.FatalFailure) { throw new OperationCanceledException("Channel has reached FatalFailure state."); } await WaitForStateChangedAsync(currentState, deadline); currentState = handle.CheckConnectivityState(false); } } /// /// Waits until there are no more active calls for this channel and then cleans up /// resources used by this channel. /// public async Task ShutdownAsync() { lock (myLock) { Preconditions.CheckState(!shutdownRequested); shutdownRequested = true; } var activeCallCount = activeCallCounter.Count; if (activeCallCount > 0) { Logger.Warning("Channel shutdown was called but there are still {0} active calls for that channel.", activeCallCount); } handle.Dispose(); await Task.Run(() => GrpcEnvironment.Release()); } internal ChannelSafeHandle Handle { get { return this.handle; } } internal GrpcEnvironment Environment { get { return this.environment; } } internal void AddCallReference(object call) { activeCallCounter.Increment(); bool success = false; handle.DangerousAddRef(ref success); Preconditions.CheckState(success); } internal void RemoveCallReference(object call) { handle.DangerousRelease(); activeCallCounter.Decrement(); } private static void EnsureUserAgentChannelOption(List options) { if (!options.Any((option) => option.Name == ChannelOptions.PrimaryUserAgentString)) { options.Add(new ChannelOption(ChannelOptions.PrimaryUserAgentString, GetUserAgentString())); } } private static string GetUserAgentString() { // TODO(jtattermusch): it would be useful to also provide .NET/mono version. return string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion); } } } grpc-0.11.1/src/csharp/Grpc.Core/Calls.cs0000644000175000017500000001665112600663151020146 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System.Threading.Tasks; using Grpc.Core.Internal; namespace Grpc.Core { /// /// Helper methods for generated clients to make RPC calls. /// Most users will use this class only indirectly and will be /// making calls using client object generated from protocol /// buffer definition files. /// public static class Calls { /// /// Invokes a simple remote call in a blocking fashion. /// /// The response. /// The call defintion. /// Request message. /// Type of request message. /// The of response message. public static TResponse BlockingUnaryCall(CallInvocationDetails call, TRequest req) where TRequest : class where TResponse : class { var asyncCall = new AsyncCall(call); return asyncCall.UnaryCall(req); } /// /// Invokes a simple remote call asynchronously. /// /// An awaitable call object providing access to the response. /// The call defintion. /// Request message. /// Type of request message. /// The of response message. public static AsyncUnaryCall AsyncUnaryCall(CallInvocationDetails call, TRequest req) where TRequest : class where TResponse : class { var asyncCall = new AsyncCall(call); var asyncResult = asyncCall.UnaryCallAsync(req); return new AsyncUnaryCall(asyncResult, asyncCall.ResponseHeadersAsync, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } /// /// Invokes a server streaming call asynchronously. /// In server streaming scenario, client sends on request and server responds with a stream of responses. /// /// A call object providing access to the asynchronous response stream. /// The call defintion. /// Request message. /// Type of request message. /// The of response messages. public static AsyncServerStreamingCall AsyncServerStreamingCall(CallInvocationDetails call, TRequest req) where TRequest : class where TResponse : class { var asyncCall = new AsyncCall(call); asyncCall.StartServerStreamingCall(req); var responseStream = new ClientResponseStream(asyncCall); return new AsyncServerStreamingCall(responseStream, asyncCall.ResponseHeadersAsync, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } /// /// Invokes a client streaming call asynchronously. /// In client streaming scenario, client sends a stream of requests and server responds with a single response. /// /// The call defintion. /// An awaitable call object providing access to the response. /// Type of request messages. /// The of response message. public static AsyncClientStreamingCall AsyncClientStreamingCall(CallInvocationDetails call) where TRequest : class where TResponse : class { var asyncCall = new AsyncCall(call); var resultTask = asyncCall.ClientStreamingCallAsync(); var requestStream = new ClientRequestStream(asyncCall); return new AsyncClientStreamingCall(requestStream, resultTask, asyncCall.ResponseHeadersAsync, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } /// /// Invokes a duplex streaming call asynchronously. /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses. /// The response stream is completely independent and both side can be sending messages at the same time. /// /// A call object providing access to the asynchronous request and response streams. /// The call definition. /// Type of request messages. /// Type of reponse messages. public static AsyncDuplexStreamingCall AsyncDuplexStreamingCall(CallInvocationDetails call) where TRequest : class where TResponse : class { var asyncCall = new AsyncCall(call); asyncCall.StartDuplexStreamingCall(); var requestStream = new ClientRequestStream(asyncCall); var responseStream = new ClientResponseStream(asyncCall); return new AsyncDuplexStreamingCall(requestStream, responseStream, asyncCall.ResponseHeadersAsync, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } } } grpc-0.11.1/src/csharp/Grpc.Core/Grpc.Core.csproj0000644000175000017500000002136612600663151021564 0ustar apollockapollock Debug AnyCPU {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Library Grpc.Core Grpc.Core v4.5 8bb563fb bin\$(Configuration)\Grpc.Core.Xml true full false bin\Debug DEBUG; prompt 4 pdbonly true bin\Release prompt 4 pdbonly true bin\ReleaseSigned SIGNED prompt 4 True C:\keys\Grpc.snk ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll PreserveNewest This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. grpc-0.11.1/src/csharp/Grpc.Core/Marshaller.cs0000644000175000017500000000734112600663151021176 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Encapsulates the logic for serializing and deserializing messages. /// public class Marshaller { readonly Func serializer; readonly Func deserializer; /// /// Initializes a new marshaller. /// /// Function that will be used to serialize messages. /// Function that will be used to deserialize messages. public Marshaller(Func serializer, Func deserializer) { this.serializer = Preconditions.CheckNotNull(serializer, "serializer"); this.deserializer = Preconditions.CheckNotNull(deserializer, "deserializer"); } /// /// Gets the serializer function. /// public Func Serializer { get { return this.serializer; } } /// /// Gets the deserializer function. /// public Func Deserializer { get { return this.deserializer; } } } /// /// Utilities for creating marshallers. /// public static class Marshallers { /// /// Creates a marshaller from specified serializer and deserializer. /// public static Marshaller Create(Func serializer, Func deserializer) { return new Marshaller(serializer, deserializer); } /// /// Returns a marshaller for string type. This is useful for testing. /// public static Marshaller StringMarshaller { get { return new Marshaller(System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.UTF8.GetString); } } } } grpc-0.11.1/src/csharp/Grpc.Core/RpcException.cs0000644000175000017500000000543112600663151021505 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.Core { /// /// Thrown when remote procedure call fails. Every RpcException is associated with a resulting of the call. /// public class RpcException : Exception { private readonly Status status; /// /// Creates a new RpcException associated with given status. /// /// Resulting status of a call. public RpcException(Status status) : base(status.ToString()) { this.status = status; } /// /// Creates a new RpcException associated with given status and message. /// /// Resulting status of a call. /// The exception message. public RpcException(Status status, string message) : base(message) { this.status = status; } /// /// Resulting status of the call. /// public Status Status { get { return status; } } } } grpc-0.11.1/src/csharp/Grpc.Core/KeyCertificatePair.cs0000644000175000017500000000557612600663151022623 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Key certificate pair (in PEM encoding). /// public sealed class KeyCertificatePair { readonly string certificateChain; readonly string privateKey; /// /// Creates a new certificate chain - private key pair. /// /// PEM encoded certificate chain. /// PEM encoded private key. public KeyCertificatePair(string certificateChain, string privateKey) { this.certificateChain = Preconditions.CheckNotNull(certificateChain, "certificateChain"); this.privateKey = Preconditions.CheckNotNull(privateKey, "privateKey"); } /// /// PEM encoded certificate chain. /// public string CertificateChain { get { return certificateChain; } } /// /// PEM encoded private key. /// public string PrivateKey { get { return privateKey; } } } } grpc-0.11.1/src/csharp/Grpc.Core/IClientStreamWriter.cs0000644000175000017500000000423212600663151023000 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Grpc.Core { /// /// Client-side writable stream of messages with Close capability. /// /// The message type. public interface IClientStreamWriter : IAsyncStreamWriter { /// /// Completes/closes the stream. Can only be called once there is no pending write. No writes should follow calling this. /// Task CompleteAsync(); } } grpc-0.11.1/src/csharp/Grpc.Core/ServerMethods.cs0000644000175000017500000000701612600663151021675 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System.Threading.Tasks; namespace Grpc.Core { /// /// Server-side handler for unary call. /// /// Request message type for this method. /// Response message type for this method. public delegate Task UnaryServerMethod(TRequest request, ServerCallContext context) where TRequest : class where TResponse : class; /// /// Server-side handler for client streaming call. /// /// Request message type for this method. /// Response message type for this method. public delegate Task ClientStreamingServerMethod(IAsyncStreamReader requestStream, ServerCallContext context) where TRequest : class where TResponse : class; /// /// Server-side handler for server streaming call. /// /// Request message type for this method. /// Response message type for this method. public delegate Task ServerStreamingServerMethod(TRequest request, IServerStreamWriter responseStream, ServerCallContext context) where TRequest : class where TResponse : class; /// /// Server-side handler for bidi streaming call. /// /// Request message type for this method. /// Response message type for this method. public delegate Task DuplexStreamingServerMethod(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) where TRequest : class where TResponse : class; } grpc-0.11.1/src/csharp/Grpc.Core/WriteOptions.cs0000644000175000017500000000577512600663151021563 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.Core { /// /// Flags for write operations. /// [Flags] public enum WriteFlags { /// /// Hint that the write may be buffered and need not go out on the wire immediately. /// gRPC is free to buffer the message until the next non-buffered /// write, or until write stream completion, but it need not buffer completely or at all. /// BufferHint = 0x1, /// /// Force compression to be disabled for a particular write. /// NoCompress = 0x2 } /// /// Options for write operations. /// public class WriteOptions { /// /// Default write options. /// public static readonly WriteOptions Default = new WriteOptions(); private WriteFlags flags; /// /// Initializes a new instance of WriteOptions class. /// /// The write flags. public WriteOptions(WriteFlags flags = default(WriteFlags)) { this.flags = flags; } /// /// Gets the write flags. /// public WriteFlags Flags { get { return this.flags; } } } } grpc-0.11.1/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs0000644000175000017500000001024412600663151024012 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading.Tasks; namespace Grpc.Core { /// /// Return type for server streaming calls. /// /// Response message type for this call. public sealed class AsyncServerStreamingCall : IDisposable { readonly IAsyncStreamReader responseStream; readonly Task responseHeadersAsync; readonly Func getStatusFunc; readonly Func getTrailersFunc; readonly Action disposeAction; internal AsyncServerStreamingCall(IAsyncStreamReader responseStream, Task responseHeadersAsync, Func getStatusFunc, Func getTrailersFunc, Action disposeAction) { this.responseStream = responseStream; this.responseHeadersAsync = responseHeadersAsync; this.getStatusFunc = getStatusFunc; this.getTrailersFunc = getTrailersFunc; this.disposeAction = disposeAction; } /// /// Async stream to read streaming responses. /// public IAsyncStreamReader ResponseStream { get { return responseStream; } } /// /// Asynchronous access to response headers. /// public Task ResponseHeadersAsync { get { return this.responseHeadersAsync; } } /// /// Gets the call status if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Status GetStatus() { return getStatusFunc(); } /// /// Gets the call trailing metadata if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Metadata GetTrailers() { return getTrailersFunc(); } /// /// Provides means to cleanup after the call. /// If the call has already finished normally (response stream has been fully read), doesn't do anything. /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. /// As a result, all resources being used by the call should be released eventually. /// public void Dispose() { disposeAction.Invoke(); } } } grpc-0.11.1/src/csharp/Grpc.Core/Credentials.cs0000644000175000017500000001151512600663151021337 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.Core.Internal; namespace Grpc.Core { /// /// Client-side credentials. Used for creation of a secure channel. /// public abstract class Credentials { static readonly Credentials InsecureInstance = new InsecureCredentialsImpl(); /// /// Returns instance of credential that provides no security and /// will result in creating an unsecure channel with no encryption whatsoever. /// public static Credentials Insecure { get { return InsecureInstance; } } /// /// Creates native object for the credentials. May return null if insecure channel /// should be created. /// /// The native credentials. internal abstract CredentialsSafeHandle ToNativeCredentials(); private sealed class InsecureCredentialsImpl : Credentials { internal override CredentialsSafeHandle ToNativeCredentials() { return null; } } } /// /// Client-side SSL credentials. /// public sealed class SslCredentials : Credentials { readonly string rootCertificates; readonly KeyCertificatePair keyCertificatePair; /// /// Creates client-side SSL credentials loaded from /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable. /// If that fails, gets the roots certificates from a well known place on disk. /// public SslCredentials() : this(null, null) { } /// /// Creates client-side SSL credentials from /// a string containing PEM encoded root certificates. /// public SslCredentials(string rootCertificates) : this(rootCertificates, null) { } /// /// Creates client-side SSL credentials. /// /// string containing PEM encoded server root certificates. /// a key certificate pair. public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair) { this.rootCertificates = rootCertificates; this.keyCertificatePair = keyCertificatePair; } /// /// PEM encoding of the server root certificates. /// public string RootCertificates { get { return this.rootCertificates; } } /// /// Client side key and certificate pair. /// If null, client will not use key and certificate pair. /// public KeyCertificatePair KeyCertificatePair { get { return this.keyCertificatePair; } } internal override CredentialsSafeHandle ToNativeCredentials() { return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); } } } grpc-0.11.1/src/csharp/Grpc.Core/packages.config0000644000175000017500000000047512600663151021523 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.Core/ChannelState.cs0000644000175000017500000000451112600663151021451 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.Core { /// /// Connectivity state of a channel. /// Based on grpc_connectivity_state from grpc/grpc.h /// public enum ChannelState { /// /// Channel is idle /// Idle, /// /// Channel is connecting /// Connecting, /// /// Channel is ready for work /// Ready, /// /// Channel has seen a failure but expects to recover /// TransientFailure, /// /// Channel has seen a failure that it cannot recover from /// FatalFailure } } grpc-0.11.1/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs0000644000175000017500000001164212600663151023765 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace Grpc.Core { /// /// Return type for client streaming calls. /// /// Request message type for this call. /// Response message type for this call. public sealed class AsyncClientStreamingCall : IDisposable { readonly IClientStreamWriter requestStream; readonly Task responseAsync; readonly Task responseHeadersAsync; readonly Func getStatusFunc; readonly Func getTrailersFunc; readonly Action disposeAction; internal AsyncClientStreamingCall(IClientStreamWriter requestStream, Task responseAsync, Task responseHeadersAsync, Func getStatusFunc, Func getTrailersFunc, Action disposeAction) { this.requestStream = requestStream; this.responseAsync = responseAsync; this.responseHeadersAsync = responseHeadersAsync; this.getStatusFunc = getStatusFunc; this.getTrailersFunc = getTrailersFunc; this.disposeAction = disposeAction; } /// /// Asynchronous call result. /// public Task ResponseAsync { get { return this.responseAsync; } } /// /// Asynchronous access to response headers. /// public Task ResponseHeadersAsync { get { return this.responseHeadersAsync; } } /// /// Async stream to send streaming requests. /// public IClientStreamWriter RequestStream { get { return requestStream; } } /// /// Allows awaiting this object directly. /// /// public TaskAwaiter GetAwaiter() { return responseAsync.GetAwaiter(); } /// /// Gets the call status if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Status GetStatus() { return getStatusFunc(); } /// /// Gets the call trailing metadata if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Metadata GetTrailers() { return getTrailersFunc(); } /// /// Provides means to cleanup after the call. /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. /// As a result, all resources being used by the call should be released eventually. /// public void Dispose() { disposeAction.Invoke(); } } } grpc-0.11.1/src/csharp/Grpc.Core/Properties/0000755000175000017500000000000012600663151020704 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs0000644000175000017500000000154212600663151023630 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Core")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] #if SIGNED [assembly: InternalsVisibleTo("Grpc.Core.Tests,PublicKey=" + "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" + "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" + "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" + "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")] #else [assembly: InternalsVisibleTo("Grpc.Core.Tests")] #endifgrpc-0.11.1/src/csharp/Grpc.Core/.gitignore0000644000175000017500000000001012600663151020527 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/Grpc.Core/Logging/0000755000175000017500000000000012600663151020136 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs0000644000175000017500000001211112600663151023223 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; namespace Grpc.Core.Logging { /// Logger that logs to System.Console. public class ConsoleLogger : ILogger { readonly Type forType; readonly string forTypeString; /// Creates a console logger not associated to any specific type. public ConsoleLogger() : this(null) { } /// Creates a console logger that logs messsage specific for given type. private ConsoleLogger(Type forType) { this.forType = forType; if (forType != null) { var namespaceStr = forType.Namespace ?? ""; if (namespaceStr.Length > 0) { namespaceStr += "."; } this.forTypeString = namespaceStr + forType.Name + " "; } else { this.forTypeString = ""; } } /// /// Returns a logger associated with the specified type. /// public ILogger ForType() { if (typeof(T) == forType) { return this; } return new ConsoleLogger(typeof(T)); } /// Logs a message with severity Debug. public void Debug(string message) { Log("D", message); } /// Logs a formatted message with severity Debug. public void Debug(string format, params object[] formatArgs) { Debug(string.Format(format, formatArgs)); } /// Logs a message with severity Info. public void Info(string message) { Log("I", message); } /// Logs a formatted message with severity Info. public void Info(string format, params object[] formatArgs) { Info(string.Format(format, formatArgs)); } /// Logs a message with severity Warning. public void Warning(string message) { Log("W", message); } /// Logs a formatted message with severity Warning. public void Warning(string format, params object[] formatArgs) { Warning(string.Format(format, formatArgs)); } /// Logs a message and an associated exception with severity Warning. public void Warning(Exception exception, string message) { Warning(message + " " + exception); } /// Logs a message with severity Error. public void Error(string message) { Log("E", message); } /// Logs a formatted message with severity Error. public void Error(string format, params object[] formatArgs) { Error(string.Format(format, formatArgs)); } /// Logs a message and an associated exception with severity Error. public void Error(Exception exception, string message) { Error(message + " " + exception); } private void Log(string severityString, string message) { Console.Error.WriteLine("{0}{1} {2}{3}", severityString, DateTime.Now, forTypeString, message); } } } grpc-0.11.1/src/csharp/Grpc.Core/Logging/ILogger.cs0000644000175000017500000000616212600663151022022 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; namespace Grpc.Core.Logging { /// For logging messages. public interface ILogger { /// Returns a logger associated with the specified type. ILogger ForType(); /// Logs a message with severity Debug. void Debug(string message); /// Logs a formatted message with severity Debug. void Debug(string format, params object[] formatArgs); /// Logs a message with severity Info. void Info(string message); /// Logs a formatted message with severity Info. void Info(string format, params object[] formatArgs); /// Logs a message with severity Warning. void Warning(string message); /// Logs a formatted message with severity Warning. void Warning(string format, params object[] formatArgs); /// Logs a message and an associated exception with severity Warning. void Warning(Exception exception, string message); /// Logs a message with severity Error. void Error(string message); /// Logs a formatted message with severity Error. void Error(string format, params object[] formatArgs); /// Logs a message and an associated exception with severity Error. void Error(Exception exception, string message); } } grpc-0.11.1/src/csharp/Grpc.Core/CallOptions.cs0000644000175000017500000001553712600663151021341 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Threading; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Options for calls made by client. /// public struct CallOptions { Metadata headers; DateTime? deadline; CancellationToken cancellationToken; WriteOptions writeOptions; ContextPropagationToken propagationToken; /// /// Creates a new instance of CallOptions struct. /// /// Headers to be sent with the call. /// Deadline for the call to finish. null means no deadline. /// Can be used to request cancellation of the call. /// Write options that will be used for this call. /// Context propagation token obtained from . public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken), WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null) { this.headers = headers; this.deadline = deadline; this.cancellationToken = cancellationToken; this.writeOptions = writeOptions; this.propagationToken = propagationToken; } /// /// Headers to send at the beginning of the call. /// public Metadata Headers { get { return headers; } } /// /// Call deadline. /// public DateTime? Deadline { get { return deadline; } } /// /// Token that can be used for cancelling the call. /// public CancellationToken CancellationToken { get { return cancellationToken; } } /// /// Write options that will be used for this call. /// public WriteOptions WriteOptions { get { return this.writeOptions; } } /// /// Token for propagating parent call context. /// public ContextPropagationToken PropagationToken { get { return this.propagationToken; } } /// /// Returns new instance of with /// Headers set to the value provided. Values of all other fields are preserved. /// /// The headers. public CallOptions WithHeaders(Metadata headers) { var newOptions = this; newOptions.headers = headers; return newOptions; } /// /// Returns new instance of with /// Deadline set to the value provided. Values of all other fields are preserved. /// /// The deadline. public CallOptions WithDeadline(DateTime deadline) { var newOptions = this; newOptions.deadline = deadline; return newOptions; } /// /// Returns new instance of with /// CancellationToken set to the value provided. Values of all other fields are preserved. /// /// The cancellation token. public CallOptions WithCancellationToken(CancellationToken cancellationToken) { var newOptions = this; newOptions.cancellationToken = cancellationToken; return newOptions; } /// /// Returns a new instance of with /// all previously unset values set to their defaults and deadline and cancellation /// token propagated when appropriate. /// internal CallOptions Normalize() { var newOptions = this; if (propagationToken != null) { if (propagationToken.Options.IsPropagateDeadline) { Preconditions.CheckArgument(!newOptions.deadline.HasValue, "Cannot propagate deadline from parent call. The deadline has already been set explicitly."); newOptions.deadline = propagationToken.ParentDeadline; } if (propagationToken.Options.IsPropagateCancellation) { Preconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled, "Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value."); } } newOptions.headers = newOptions.headers ?? Metadata.Empty; newOptions.deadline = newOptions.deadline ?? DateTime.MaxValue; return newOptions; } } } grpc-0.11.1/src/csharp/Grpc.Core/ServerCredentials.cs0000644000175000017500000001364412600663151022533 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Server side credentials. /// public abstract class ServerCredentials { static readonly ServerCredentials InsecureInstance = new InsecureServerCredentialsImpl(); /// /// Returns instance of credential that provides no security and /// will result in creating an unsecure server port with no encryption whatsoever. /// public static ServerCredentials Insecure { get { return InsecureInstance; } } /// /// Creates native object for the credentials. /// /// The native credentials. internal abstract ServerCredentialsSafeHandle ToNativeCredentials(); private sealed class InsecureServerCredentialsImpl : ServerCredentials { internal override ServerCredentialsSafeHandle ToNativeCredentials() { return null; } } } /// /// Server-side SSL credentials. /// public class SslServerCredentials : ServerCredentials { readonly IList keyCertificatePairs; readonly string rootCertificates; readonly bool forceClientAuth; /// /// Creates server-side SSL credentials. /// /// Key-certificates to use. /// PEM encoded client root certificates used to authenticate client. /// If true, client will be rejected unless it proves its unthenticity using against rootCertificates. public SslServerCredentials(IEnumerable keyCertificatePairs, string rootCertificates, bool forceClientAuth) { this.keyCertificatePairs = new List(keyCertificatePairs).AsReadOnly(); Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0, "At least one KeyCertificatePair needs to be provided."); if (forceClientAuth) { Preconditions.CheckNotNull(rootCertificates, "Cannot force client authentication unless you provide rootCertificates."); } this.rootCertificates = rootCertificates; this.forceClientAuth = forceClientAuth; } /// /// Creates server-side SSL credentials. /// This constructor should be use if you do not wish to autheticate client /// using client root certificates. /// /// Key-certificates to use. public SslServerCredentials(IEnumerable keyCertificatePairs) : this(keyCertificatePairs, null, false) { } /// /// Key-certificate pairs. /// public IList KeyCertificatePairs { get { return this.keyCertificatePairs; } } /// /// PEM encoded client root certificates. /// public string RootCertificates { get { return this.rootCertificates; } } /// /// If true, the authenticity of client check will be enforced. /// public bool ForceClientAuthentication { get { return this.forceClientAuth; } } internal override ServerCredentialsSafeHandle ToNativeCredentials() { int count = keyCertificatePairs.Count; string[] certChains = new string[count]; string[] keys = new string[count]; for (int i = 0; i < count; i++) { certChains[i] = keyCertificatePairs[i].CertificateChain; keys[i] = keyCertificatePairs[i].PrivateKey; } return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, forceClientAuth); } } } grpc-0.11.1/src/csharp/Grpc.Core/ChannelOptions.cs0000644000175000017500000001660012600663151022026 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core { /// /// Channel option specified when creating a channel. /// Corresponds to grpc_channel_args from grpc/grpc.h. /// public sealed class ChannelOption { /// /// Type of ChannelOption. /// public enum OptionType { /// /// Channel option with integer value. /// Integer, /// /// Channel option with string value. /// String } private readonly OptionType type; private readonly string name; private readonly int intValue; private readonly string stringValue; /// /// Creates a channel option with a string value. /// /// Name. /// String value. public ChannelOption(string name, string stringValue) { this.type = OptionType.String; this.name = Preconditions.CheckNotNull(name, "name"); this.stringValue = Preconditions.CheckNotNull(stringValue, "stringValue"); } /// /// Creates a channel option with an integer value. /// /// Name. /// Integer value. public ChannelOption(string name, int intValue) { this.type = OptionType.Integer; this.name = Preconditions.CheckNotNull(name, "name"); this.intValue = intValue; } /// /// Gets the type of the ChannelOption. /// public OptionType Type { get { return type; } } /// /// Gets the name of the ChannelOption. /// public string Name { get { return name; } } /// /// Gets the integer value the ChannelOption. /// public int IntValue { get { Preconditions.CheckState(type == OptionType.Integer); return intValue; } } /// /// Gets the string value the ChannelOption. /// public string StringValue { get { Preconditions.CheckState(type == OptionType.String); return stringValue; } } } /// /// Defines names of supported channel options. /// public static class ChannelOptions { /// Override SSL target check. Only to be used for testing. public const string SslTargetNameOverride = "grpc.ssl_target_name_override"; /// Enable census for tracing and stats collection public const string Census = "grpc.census"; /// Maximum number of concurrent incoming streams to allow on a http2 connection public const string MaxConcurrentStreams = "grpc.max_concurrent_streams"; /// Maximum message length that the channel can receive public const string MaxMessageLength = "grpc.max_message_length"; /// Initial sequence number for http2 transports public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number"; /// Default authority for calls. public const string DefaultAuthority = "grpc.default_authority"; /// Primary user agent: goes at the start of the user-agent metadata public const string PrimaryUserAgentString = "grpc.primary_user_agent"; /// Secondary user agent: goes at the end of the user-agent metadata public const string SecondaryUserAgentString = "grpc.secondary_user_agent"; /// /// Creates native object for a collection of channel options. /// /// The native channel arguments. internal static ChannelArgsSafeHandle CreateChannelArgs(List options) { if (options == null || options.Count == 0) { return ChannelArgsSafeHandle.CreateNull(); } ChannelArgsSafeHandle nativeArgs = null; try { nativeArgs = ChannelArgsSafeHandle.Create(options.Count); for (int i = 0; i < options.Count; i++) { var option = options[i]; if (option.Type == ChannelOption.OptionType.Integer) { nativeArgs.SetInteger(i, option.Name, option.IntValue); } else if (option.Type == ChannelOption.OptionType.String) { nativeArgs.SetString(i, option.Name, option.StringValue); } else { throw new InvalidOperationException("Unknown option type"); } } return nativeArgs; } catch (Exception) { if (nativeArgs != null) { nativeArgs.Dispose(); } throw; } } } } grpc-0.11.1/src/csharp/build_packages.bat0000644000175000017500000000227612600663151020422 0ustar apollockapollock@rem Builds gRPC NuGet packages @rem Current package versions set VERSION=0.7.1 set CORE_VERSION=0.11.1 set PROTOBUF_VERSION=3.0.0-alpha4 @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well. set VERSION_WITH_BETA=%VERSION%-beta @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe setlocal cd ..\..\vsprojects\nuget_package @call buildall.bat || goto :error endlocal @call buildall.bat BUILD_SIGNED || goto :error @call ..\..\vsprojects\build_plugins.bat || goto :error %NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error %NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error %NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error goto :EOF :error echo Failed! exit /b %errorlevel% grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/0000755000175000017500000000000012600663151022746 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/Program.cs0000644000175000017500000000341112600663151024703 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; namespace Grpc.IntegrationTesting.Server { class Program { public static void Main(string[] args) { InteropServer.Run(args); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj0000644000175000017500000000517312600663151032156 0ustar apollockapollock Debug AnyCPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D} Exe Grpc.IntegrationTesting.Server Grpc.IntegrationTesting.Server Grpc.IntegrationTesting.Server.Program v4.5 true full false bin\Debug DEBUG; prompt 4 AnyCPU pdbonly true bin\Release prompt 4 AnyCPU pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk Version.cs {C61154BA-DD4A-4838-8420-0162A28925E0} Grpc.IntegrationTesting {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/app.config0000644000175000017500000000162112600663151024715 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/Properties/0000755000175000017500000000000012600663151025102 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs0000644000175000017500000000061412600663151030025 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.IntegrationTesting.Server")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Server/.gitignore0000644000175000017500000000001112600663151024726 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/Grpc.Examples.MathClient/0000755000175000017500000000000012600663151021465 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples.MathClient/MathClient.cs0000644000175000017500000000445012600663151024047 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading; using Grpc.Core; namespace Math { class MathClient { public static void Main(string[] args) { var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure); Math.IMathClient client = new Math.MathClient(channel); MathExamples.DivExample(client); MathExamples.DivAsyncExample(client).Wait(); MathExamples.FibExample(client).Wait(); MathExamples.SumExample(client).Wait(); MathExamples.DivManyExample(client).Wait(); MathExamples.DependendRequestsExample(client).Wait(); channel.ShutdownAsync().Wait(); } } } grpc-0.11.1/src/csharp/Grpc.Examples.MathClient/Properties/0000755000175000017500000000000012600663151023621 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs0000644000175000017500000000060612600663151026545 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Examples.MathClient")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.Examples.MathClient/.gitignore0000644000175000017500000000001012600663151023444 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj0000644000175000017500000000464412600663151027416 0ustar apollockapollock Debug AnyCPU 10.0.0 2.0 {61ECB8EE-0C96-4F8E-B187-8E4D227417C0} Exe math MathClient v4.5 true full false bin\Debug DEBUG; prompt 4 pdbonly true bin\Release prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core {7DC1433E-3225-42C7-B7EA-546D56E27A4B} Grpc.Examples grpc-0.11.1/src/csharp/doc/0000755000175000017500000000000012600663151015533 5ustar apollockapollockgrpc-0.11.1/src/csharp/doc/README.md0000644000175000017500000000010312600663151017004 0ustar apollockapollock SandCastle project files to generate HTML reference documentation.grpc-0.11.1/src/csharp/doc/grpc_csharp_public.shfbproj0000644000175000017500000001102312600663151023120 0ustar apollockapollock Debug AnyCPU 2.0 {77e3da09-fc92-486f-a90a-99ca788e8b59} 2015.6.5.0 Documentation Documentation Documentation .NET Framework 4.5 ..\..\..\doc\ref\csharp\html en-US OnlyWarningsAndErrors Website False True False True 1.0.0.0 2 False Standard Blank True VS2013 False MemberName gRPC C# AboveNamespaces Documentation Provides OAuth2 based authentication for gRPC. <c>Grpc.Auth</c> currently consists of a set of very lightweight wrappers and uses C# <a href="https://www.nuget.org/packages/Google.Apis.Auth/">Google.Apis.Auth</a> library. Main namespace for gRPC C# functionality. Contains concepts representing both client side and server side gRPC logic. <seealso cref="Grpc.Core.Channel"/> <seealso cref="Grpc.Core.Server"/> Provides functionality to redirect gRPC logs to application-specified destination. Various utilities for gRPC C#. Summary, Parameter, AutoDocumentCtors, Namespace, TypeParameter, AutoDocumentDispose OnBuildSuccess grpc-0.11.1/src/csharp/Grpc.Examples.MathServer/0000755000175000017500000000000012600663151021515 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples.MathServer/MathServer.cs0000644000175000017500000000445212600663151024131 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Runtime.InteropServices; using System.Threading; using Grpc.Core; namespace Math { class MainClass { const string Host = "0.0.0.0"; const int Port = 23456; public static void Main(string[] args) { Server server = new Server { Services = { Math.BindService(new MathServiceImpl()) }, Ports = { { Host, Port, ServerCredentials.Insecure } } }; server.Start(); Console.WriteLine("MathServer listening on port " + Port); Console.WriteLine("Press any key to stop the server..."); Console.ReadKey(); server.ShutdownAsync().Wait(); } } } grpc-0.11.1/src/csharp/Grpc.Examples.MathServer/Properties/0000755000175000017500000000000012600663151023651 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs0000644000175000017500000000060612600663151026575 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.Examples.MathServer")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.Examples.MathServer/.gitignore0000644000175000017500000000001012600663151023474 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj0000644000175000017500000000467012600663151027475 0ustar apollockapollock Debug AnyCPU 10.0.0 2.0 {BF62FE08-373A-43D6-9D73-41CAA38B7011} Exe Grpc.Examples.MathServer MathServer v4.5 true full false bin\Debug DEBUG; prompt 4 pdbonly true bin\Release prompt 4 pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk Version.cs {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core {7DC1433E-3225-42C7-B7EA-546D56E27A4B} Grpc.Examples grpc-0.11.1/src/csharp/generate_proto_csharp.sh0000755000175000017500000000426312600663151021707 0ustar apollockapollock#!/bin/sh # 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. # Regenerates gRPC service stubs from proto files. set +e cd $(dirname $0) PROTOC=../../bins/opt/protobuf/protoc PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin EXAMPLES_DIR=Grpc.Examples INTEROP_DIR=Grpc.IntegrationTesting HEALTHCHECK_DIR=Grpc.HealthCheck $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \ -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto $PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \ -I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \ -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/0000755000175000017500000000000012600663151022716 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/Program.cs0000644000175000017500000000345012600663151024656 0ustar apollockapollock#region Copyright notice and license // Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using Grpc.IntegrationTesting; namespace Grpc.IntegrationTesting.Client { class Program { public static void Main(string[] args) { InteropClient.Run(args); } } } grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj0000644000175000017500000000517312600663151032076 0ustar apollockapollock Debug AnyCPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9} Exe Grpc.IntegrationTesting.Client Grpc.IntegrationTesting.Client Grpc.IntegrationTesting.Client.Program v4.5 true full false bin\Debug DEBUG; prompt 4 AnyCPU pdbonly true bin\Release prompt 4 AnyCPU pdbonly true bin\ReleaseSigned prompt 4 True C:\keys\Grpc.snk Version.cs {C61154BA-DD4A-4838-8420-0162A28925E0} Grpc.IntegrationTesting {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} Grpc.Core grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/app.config0000644000175000017500000000162112600663151024665 0ustar apollockapollock grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/Properties/0000755000175000017500000000000012600663151025052 5ustar apollockapollockgrpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs0000644000175000017500000000061412600663151027775 0ustar apollockapollockusing System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Grpc.IntegrationTesting.Client")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] grpc-0.11.1/src/csharp/Grpc.IntegrationTesting.Client/.gitignore0000644000175000017500000000001112600663151024676 0ustar apollockapollockbin obj grpc-0.11.1/src/csharp/.gitignore0000644000175000017500000000017712600663151016763 0ustar apollockapollock*.userprefs *.csproj.user StyleCop.Cache test-results packages Grpc.v12.suo Grpc.sdf TestResult.xml /TestResults .vs/ *.nupkg grpc-0.11.1/src/csharp/Grpc.nuspec0000644000175000017500000000160412600663151017101 0ustar apollockapollock Grpc gRPC C# C# implementation of gRPC - an RPC library and framework C# implementation of gRPC - an RPC library and framework. See project site for more info. $version$ Google Inc. grpc-packages https://github.com/grpc/grpc/blob/master/LICENSE https://github.com/grpc/grpc false Release $version$ of gRPC C# Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 grpc-0.11.1/src/csharp/Grpc.Tools.nuspec0000644000175000017500000000164312600663151020203 0ustar apollockapollock Grpc.Tools gRPC C# Tools Tools for C# implementation of gRPC - an RPC library and framework Precompiled Windows binary for generating gRPC client/server code $version$ Google Inc. grpc-packages https://github.com/grpc/grpc/blob/master/LICENSE https://github.com/grpc/grpc false grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$ Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 grpc-0.11.1/src/core/0000755000175000017500000000000012600663151014436 5ustar apollockapollockgrpc-0.11.1/src/core/README.md0000644000175000017500000000036312600663151015717 0ustar apollockapollock#Overview This directory contains source code for shared C library. Libraries in other languages in this repository (C++, Ruby, Python, PHP, NodeJS, Objective-C) are layered on top of this library. #Status Alpha : Ready for early adopters grpc-0.11.1/src/core/surface/0000755000175000017500000000000012600663151016066 5ustar apollockapollockgrpc-0.11.1/src/core/surface/lame_client.c0000644000175000017500000001350212600663151020507 0ustar apollockapollock/* * * 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 #include #include "src/core/channel/channel_stack.h" #include "src/core/support/string.h" #include "src/core/surface/channel.h" #include "src/core/surface/call.h" #include #include typedef struct { grpc_linked_mdelem status; grpc_linked_mdelem details; } call_data; typedef struct { grpc_mdctx *mdctx; grpc_channel *master; grpc_status_code error_code; const char *error_message; } channel_data; static void lame_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); if (op->send_ops != NULL) { grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops); op->on_done_send->cb(op->on_done_send->cb_arg, 0); } if (op->recv_ops != NULL) { char tmp[GPR_LTOA_MIN_BUFSIZE]; grpc_metadata_batch mdb; gpr_ltoa(chand->error_code, tmp); calld->status.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-status", tmp); calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message", chand->error_message); calld->status.prev = calld->details.next = NULL; calld->status.next = &calld->details; calld->details.prev = &calld->status; mdb.list.head = &calld->status; mdb.list.tail = &calld->details; mdb.garbage.head = mdb.garbage.tail = NULL; mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME); grpc_sopb_add_metadata(op->recv_ops, mdb); *op->recv_state = GRPC_STREAM_CLOSED; op->on_done_recv->cb(op->on_done_recv->cb_arg, 1); } if (op->on_consumed != NULL) { op->on_consumed->cb(op->on_consumed->cb_arg, 0); } } static char *lame_get_peer(grpc_call_element *elem) { channel_data *chand = elem->channel_data; return grpc_channel_get_target(chand->master); } static void lame_start_transport_op(grpc_channel_element *elem, grpc_transport_op *op) { if (op->on_connectivity_state_change) { GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE); *op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE; op->on_connectivity_state_change->cb( op->on_connectivity_state_change->cb_arg, 1); } if (op->on_consumed != NULL) { op->on_consumed->cb(op->on_consumed->cb_arg, 1); } } static void init_call_elem(grpc_call_element *elem, const void *transport_server_data, grpc_transport_stream_op *initial_op) { if (initial_op) { grpc_transport_stream_op_finish_with_failure(initial_op); } } static void destroy_call_elem(grpc_call_element *elem) {} static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { channel_data *chand = elem->channel_data; GPR_ASSERT(is_first); GPR_ASSERT(is_last); chand->mdctx = mdctx; chand->master = master; } static void destroy_channel_elem(grpc_channel_element *elem) {} static const grpc_channel_filter lame_filter = { lame_start_transport_stream_op, lame_start_transport_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, lame_get_peer, "lame-client", }; #define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) grpc_channel *grpc_lame_client_channel_create(const char *target, grpc_status_code error_code, const char *error_message) { grpc_channel *channel; grpc_channel_element *elem; channel_data *chand; static const grpc_channel_filter *filters[] = {&lame_filter}; channel = grpc_channel_create_from_filters(target, filters, 1, NULL, grpc_mdctx_create(), 1); elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); GPR_ASSERT(elem->filter == &lame_filter); chand = (channel_data *)elem->channel_data; chand->error_code = error_code; chand->error_message = error_message; return channel; } grpc-0.11.1/src/core/surface/version.c0000644000175000017500000000332112600663151017716 0ustar apollockapollock/* * * 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. * */ /* This file is autogenerated from: templates/src/core/surface/version.c.template */ #include const char *grpc_version_string(void) { return "0.11.0.0"; } grpc-0.11.1/src/core/surface/event_string.h0000644000175000017500000000352012600663151020746 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H #define GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H #include /* Returns a string describing an event. Must be later freed with gpr_free() */ char *grpc_event_string(grpc_event *ev); #endif /* GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H */ grpc-0.11.1/src/core/surface/byte_buffer.c0000644000175000017500000000702312600663151020530 0ustar apollockapollock/* * * 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 #include #include grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices, size_t nslices) { return grpc_raw_compressed_byte_buffer_create(slices, nslices, GRPC_COMPRESS_NONE); } grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create( gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) { size_t i; grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); bb->type = GRPC_BB_RAW; bb->data.raw.compression = compression; gpr_slice_buffer_init(&bb->data.raw.slice_buffer); for (i = 0; i < nslices; i++) { gpr_slice_ref(slices[i]); gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]); } return bb; } grpc_byte_buffer *grpc_raw_byte_buffer_from_reader( grpc_byte_buffer_reader *reader) { grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); gpr_slice slice; bb->type = GRPC_BB_RAW; bb->data.raw.compression = GRPC_COMPRESS_NONE; gpr_slice_buffer_init(&bb->data.raw.slice_buffer); while (grpc_byte_buffer_reader_next(reader, &slice)) { gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slice); } return bb; } grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) { switch (bb->type) { case GRPC_BB_RAW: return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices, bb->data.raw.slice_buffer.count); } gpr_log(GPR_INFO, "should never get here"); abort(); return NULL; } void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) { if (!bb) return; switch (bb->type) { case GRPC_BB_RAW: gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer); break; } free(bb); } size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) { switch (bb->type) { case GRPC_BB_RAW: return bb->data.raw.slice_buffer.length; } gpr_log(GPR_ERROR, "should never reach here"); abort(); } grpc-0.11.1/src/core/surface/call_log_batch.c0000644000175000017500000001336412600663151021156 0ustar apollockapollock/* * * 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/surface/call.h" #include "src/core/support/string.h" #include #include int grpc_trace_batch = 0; static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) { size_t i; for (i = 0; i < count; i++) { gpr_strvec_add(b, gpr_strdup("\nkey=")); gpr_strvec_add(b, gpr_strdup(md[i].key)); gpr_strvec_add(b, gpr_strdup(" value=")); gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length, GPR_DUMP_HEX | GPR_DUMP_ASCII)); } } char *grpc_op_string(const grpc_op *op) { char *tmp; char *out; gpr_strvec b; gpr_strvec_init(&b); switch (op->op) { case GRPC_OP_SEND_INITIAL_METADATA: gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA")); add_metadata(&b, op->data.send_initial_metadata.metadata, op->data.send_initial_metadata.count); break; case GRPC_OP_SEND_MESSAGE: gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message); gpr_strvec_add(&b, tmp); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT")); break; case GRPC_OP_SEND_STATUS_FROM_SERVER: gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s", op->data.send_status_from_server.status, op->data.send_status_from_server.status_details); gpr_strvec_add(&b, tmp); add_metadata(&b, op->data.send_status_from_server.trailing_metadata, op->data.send_status_from_server.trailing_metadata_count); break; case GRPC_OP_RECV_INITIAL_METADATA: gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p", op->data.recv_initial_metadata); gpr_strvec_add(&b, tmp); break; case GRPC_OP_RECV_MESSAGE: gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message); gpr_strvec_add(&b, tmp); break; case GRPC_OP_RECV_STATUS_ON_CLIENT: gpr_asprintf(&tmp, "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p", op->data.recv_status_on_client.trailing_metadata, op->data.recv_status_on_client.status, op->data.recv_status_on_client.status_details); gpr_strvec_add(&b, tmp); break; case GRPC_OP_RECV_CLOSE_ON_SERVER: gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p", op->data.recv_close_on_server.cancelled); gpr_strvec_add(&b, tmp); } out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); return out; } void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, grpc_call *call, const grpc_op *ops, size_t nops, void *tag) { char *tmp; size_t i; gpr_log(file, line, severity, "grpc_call_start_batch(call=%p, ops=%p, nops=%d, tag=%p)", call, ops, nops, tag); for (i = 0; i < nops; i++) { tmp = grpc_op_string(&ops[i]); gpr_log(file, line, severity, "ops[%d]: %s", i, tmp); gpr_free(tmp); } } void grpc_server_log_request_call(char *file, int line, gpr_log_severity severity, grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *initial_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag) { gpr_log(file, line, severity, "grpc_server_request_call(server=%p, call=%p, details=%p, " "initial_metadata=%p, cq_bound_to_call=%p, cq_for_notification=%p, " "tag=%p)", server, call, details, initial_metadata, cq_bound_to_call, cq_for_notification, tag); } void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity, grpc_server *server, grpc_completion_queue *cq, void *tag) { gpr_log(file, line, severity, "grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", server, cq, tag); } grpc-0.11.1/src/core/surface/init_unsecure.c0000644000175000017500000000315312600663151021110 0ustar apollockapollock/* * * 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/surface/init.h" void grpc_security_pre_init(void) {} grpc-0.11.1/src/core/surface/metadata_array.c0000644000175000017500000000346012600663151021213 0ustar apollockapollock/* * * 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 #include #include void grpc_metadata_array_init(grpc_metadata_array *array) { memset(array, 0, sizeof(*array)); } void grpc_metadata_array_destroy(grpc_metadata_array *array) { gpr_free(array->metadata); } grpc-0.11.1/src/core/surface/surface_trace.h0000644000175000017500000000411112600663151021042 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H #define GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H #include "src/core/debug/trace.h" #include extern int grpc_surface_trace; #define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ if (grpc_surface_trace) { \ char *_ev = grpc_event_string(event); \ gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ gpr_free(_ev); \ } #endif /* GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H */ grpc-0.11.1/src/core/surface/channel.h0000644000175000017500000000711112600663151017647 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H #define GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H #include "src/core/channel/channel_stack.h" #include "src/core/client_config/subchannel_factory.h" grpc_channel *grpc_channel_create_from_filters( const char *target, const grpc_channel_filter **filters, size_t count, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client); /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel); /** Get a (borrowed) pointer to the channel wide metadata context */ grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel); /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of status_code. The returned elem is owned by the caller. */ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int status_code); grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel); grpc_mdstr *grpc_channel_get_compression_algorithm_string( grpc_channel *channel); grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string( grpc_channel *channel); grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel); gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel); #ifdef GRPC_CHANNEL_REF_COUNT_DEBUG void grpc_channel_internal_ref(grpc_channel *channel, const char *reason); void grpc_channel_internal_unref(grpc_channel *channel, const char *reason); #define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \ grpc_channel_internal_ref(channel, reason) #define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \ grpc_channel_internal_unref(channel, reason) #else void grpc_channel_internal_ref(grpc_channel *channel); void grpc_channel_internal_unref(grpc_channel *channel); #define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \ grpc_channel_internal_ref(channel) #define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \ grpc_channel_internal_unref(channel) #endif #endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */ grpc-0.11.1/src/core/surface/byte_buffer_queue.h0000644000175000017500000000466412600663151021751 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H #define GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H #include /* TODO(ctiller): inline an element or two into this struct to avoid per-call allocations */ typedef struct { grpc_byte_buffer **data; size_t count; size_t capacity; } grpc_bbq_array; /* should be initialized by zeroing memory */ typedef struct { size_t drain_pos; grpc_bbq_array filling; grpc_bbq_array draining; size_t bytes; } grpc_byte_buffer_queue; void grpc_bbq_destroy(grpc_byte_buffer_queue *q); grpc_byte_buffer *grpc_bbq_pop(grpc_byte_buffer_queue *q); void grpc_bbq_flush(grpc_byte_buffer_queue *q); int grpc_bbq_empty(grpc_byte_buffer_queue *q); void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *bb); size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q); #endif /* GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H */ grpc-0.11.1/src/core/surface/surface_trace.c0000644000175000017500000000315312600663151021042 0ustar apollockapollock/* * * 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/surface/surface_trace.h" int grpc_surface_trace = 0; grpc-0.11.1/src/core/surface/server_chttp2.c0000644000175000017500000001147312600663151021032 0ustar apollockapollock/* * * 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 #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_server.h" #include "src/core/surface/server.h" #include "src/core/transport/chttp2_transport.h" #include #include #include static void setup_transport(void *server, grpc_transport *transport, grpc_mdctx *mdctx) { static grpc_channel_filter const *extra_filters[] = { &grpc_http_server_filter}; grpc_server_setup_transport(server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx, grpc_server_get_channel_args(server)); } static void new_transport(void *server, grpc_endpoint *tcp) { /* * Beware that the call to grpc_create_chttp2_transport() has to happen before * grpc_tcp_server_destroy(). This is fine here, but similar code * asynchronously doing a handshake instead of calling grpc_tcp_server_start() * (as in server_secure_chttp2.c) needs to add synchronization to avoid this * case. */ grpc_mdctx *mdctx = grpc_mdctx_create(); grpc_transport *transport = grpc_create_chttp2_transport( grpc_server_get_channel_args(server), tcp, mdctx, 0); setup_transport(server, transport, mdctx); grpc_chttp2_transport_start_reading(transport, NULL, 0); } /* Server callback: start listening on our ports */ static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, size_t pollset_count) { grpc_tcp_server *tcp = tcpp; grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server); } /* Server callback: destroy the tcp listener (so we don't generate further callbacks) */ static void destroy(grpc_server *server, void *tcpp) { grpc_tcp_server *tcp = tcpp; grpc_tcp_server_destroy(tcp, grpc_server_listener_destroy_done, server); } int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; size_t i; unsigned count = 0; int port_num = -1; int port_temp; resolved = grpc_blocking_resolve_address(addr, "http"); if (!resolved) { goto error; } tcp = grpc_tcp_server_create(); if (!tcp) { goto error; } for (i = 0; i < resolved->naddrs; i++) { port_temp = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len); if (port_temp >= 0) { if (port_num == -1) { port_num = port_temp; } else { GPR_ASSERT(port_num == port_temp); } count++; } } if (count == 0) { gpr_log(GPR_ERROR, "No address added out of total %d resolved", resolved->naddrs); goto error; } if (count != resolved->naddrs) { gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", count, resolved->naddrs); } grpc_resolved_addresses_destroy(resolved); /* Register with the server only upon success */ grpc_server_add_listener(server, tcp, start, destroy); return port_num; /* Error path: cleanup and return */ error: if (resolved) { grpc_resolved_addresses_destroy(resolved); } if (tcp) { grpc_tcp_server_destroy(tcp, NULL, NULL); } return 0; } grpc-0.11.1/src/core/surface/init.c0000644000175000017500000001162612600663151017203 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include "src/core/channel/channel_stack.h" #include "src/core/client_config/resolver_registry.h" #include "src/core/client_config/resolvers/dns_resolver.h" #include "src/core/client_config/resolvers/sockaddr_resolver.h" #include "src/core/debug/trace.h" #include "src/core/iomgr/iomgr.h" #include "src/core/profiling/timers.h" #include "src/core/surface/call.h" #include "src/core/surface/init.h" #include "src/core/surface/surface_trace.h" #include "src/core/transport/chttp2_transport.h" #include "src/core/transport/connectivity_state.h" #define MAX_PLUGINS 128 static gpr_once g_basic_init = GPR_ONCE_INIT; static gpr_mu g_init_mu; static int g_initializations; static void do_basic_init(void) { gpr_mu_init(&g_init_mu); g_initializations = 0; } typedef struct grpc_plugin { void (*init)(); void (*destroy)(); } grpc_plugin; static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS]; static int g_number_of_plugins = 0; void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) { GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS); g_all_of_the_plugins[g_number_of_plugins].init = init; g_all_of_the_plugins[g_number_of_plugins].destroy = destroy; g_number_of_plugins++; } void grpc_init(void) { int i; gpr_once_init(&g_basic_init, do_basic_init); gpr_mu_lock(&g_init_mu); if (++g_initializations == 1) { gpr_time_init(); grpc_resolver_registry_init("dns:///"); grpc_register_resolver_type(grpc_dns_resolver_factory_create()); grpc_register_resolver_type(grpc_ipv4_resolver_factory_create()); grpc_register_resolver_type(grpc_ipv6_resolver_factory_create()); #ifdef GPR_POSIX_SOCKET grpc_register_resolver_type(grpc_unix_resolver_factory_create()); #endif grpc_register_tracer("channel", &grpc_trace_channel); grpc_register_tracer("surface", &grpc_surface_trace); grpc_register_tracer("http", &grpc_http_trace); grpc_register_tracer("flowctl", &grpc_flowctl_trace); grpc_register_tracer("batch", &grpc_trace_batch); grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace); grpc_security_pre_init(); grpc_iomgr_init(); grpc_tracer_init("GRPC_TRACE"); /* Only initialize census if noone else has. */ if (census_enabled() == CENSUS_FEATURE_NONE) { if (census_initialize(census_supported())) { /* enable all features. */ gpr_log(GPR_ERROR, "Could not initialize census."); } } grpc_timers_global_init(); for (i = 0; i < g_number_of_plugins; i++) { if (g_all_of_the_plugins[i].init != NULL) { g_all_of_the_plugins[i].init(); } } } gpr_mu_unlock(&g_init_mu); } void grpc_shutdown(void) { int i; gpr_mu_lock(&g_init_mu); if (--g_initializations == 0) { grpc_iomgr_shutdown(); census_shutdown(); grpc_timers_global_destroy(); grpc_tracer_shutdown(); grpc_resolver_registry_shutdown(); for (i = 0; i < g_number_of_plugins; i++) { if (g_all_of_the_plugins[i].destroy != NULL) { g_all_of_the_plugins[i].destroy(); } } } gpr_mu_unlock(&g_init_mu); } int grpc_is_initialized(void) { int r; gpr_once_init(&g_basic_init, do_basic_init); gpr_mu_lock(&g_init_mu); r = g_initializations > 0; gpr_mu_unlock(&g_init_mu); return r; } grpc-0.11.1/src/core/surface/call.c0000644000175000017500000017445312600663151017163 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include #include #include "src/core/channel/channel_stack.h" #include "src/core/iomgr/alarm.h" #include "src/core/profiling/timers.h" #include "src/core/support/string.h" #include "src/core/surface/byte_buffer_queue.h" #include "src/core/surface/call.h" #include "src/core/surface/channel.h" #include "src/core/surface/completion_queue.h" /** The maximum number of completions possible. Based upon the maximum number of individually queueable ops in the batch api: - initial metadata send - message send - status/close send (depending on client/server) - initial metadata recv - message recv - status/close recv (depending on client/server) */ #define MAX_CONCURRENT_COMPLETIONS 6 typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state; typedef enum { SEND_NOTHING, SEND_INITIAL_METADATA, SEND_BUFFERED_INITIAL_METADATA, SEND_MESSAGE, SEND_BUFFERED_MESSAGE, SEND_TRAILING_METADATA_AND_FINISH, SEND_FINISH } send_action; typedef struct { grpc_ioreq_completion_func on_complete; void *user_data; int success; } completed_request; /* See request_set in grpc_call below for a description */ #define REQSET_EMPTY 'X' #define REQSET_DONE 'Y' #define MAX_SEND_INITIAL_METADATA_COUNT 3 typedef struct { /* Overall status of the operation: starts OK, may degrade to non-OK */ gpr_uint8 success; /* a bit mask of which request ops are needed (1u << opid) */ gpr_uint16 need_mask; /* a bit mask of which request ops are now completed */ gpr_uint16 complete_mask; /* Completion function to call at the end of the operation */ grpc_ioreq_completion_func on_complete; void *user_data; } reqinfo_master; /* Status data for a request can come from several sources; this enumerates them all, and acts as a priority sorting for which status to return to the application - earlier entries override later ones */ typedef enum { /* Status came from the application layer overriding whatever the wire says */ STATUS_FROM_API_OVERRIDE = 0, /* Status was created by some internal channel stack operation */ STATUS_FROM_CORE, /* Status came from 'the wire' - or somewhere below the surface layer */ STATUS_FROM_WIRE, /* Status came from the server sending status */ STATUS_FROM_SERVER_STATUS, STATUS_SOURCE_COUNT } status_source; typedef struct { gpr_uint8 is_set; grpc_status_code code; grpc_mdstr *details; } received_status; /* How far through the GRPC stream have we read? */ typedef enum { /* We are still waiting for initial metadata to complete */ READ_STATE_INITIAL = 0, /* We have gotten initial metadata, and are reading either messages or trailing metadata */ READ_STATE_GOT_INITIAL_METADATA, /* The stream is closed for reading */ READ_STATE_READ_CLOSED, /* The stream is closed for reading & writing */ READ_STATE_STREAM_CLOSED } read_state; typedef enum { WRITE_STATE_INITIAL = 0, WRITE_STATE_STARTED, WRITE_STATE_WRITE_CLOSED } write_state; struct grpc_call { grpc_completion_queue *cq; grpc_channel *channel; grpc_call *parent; grpc_call *first_child; grpc_mdctx *metadata_context; /* TODO(ctiller): share with cq if possible? */ gpr_mu mu; gpr_mu completion_mu; /* how far through the stream have we read? */ read_state read_state; /* how far through the stream have we written? */ write_state write_state; /* client or server call */ gpr_uint8 is_client; /* is the alarm set */ gpr_uint8 have_alarm; /* are we currently performing a send operation */ gpr_uint8 sending; /* are we currently performing a recv operation */ gpr_uint8 receiving; /* are we currently completing requests */ gpr_uint8 completing; /** has grpc_call_destroy been called */ gpr_uint8 destroy_called; /* pairs with completed_requests */ gpr_uint8 num_completed_requests; /* are we currently reading a message? */ gpr_uint8 reading_message; /* have we bound a pollset yet? */ gpr_uint8 bound_pollset; /* is an error status set */ gpr_uint8 error_status_set; /** should the alarm be cancelled */ gpr_uint8 cancel_alarm; /** bitmask of allocated completion events in completions */ gpr_uint8 allocated_completions; /** flag indicating that cancellation is inherited */ gpr_uint8 cancellation_is_inherited; /* flags with bits corresponding to write states allowing us to determine what was sent */ gpr_uint16 last_send_contains; /* cancel with this status on the next outgoing transport op */ grpc_status_code cancel_with_status; /* Active ioreqs. request_set and request_data contain one element per active ioreq operation. request_set[op] is an integer specifying a set of operations to which the request belongs: - if it is < GRPC_IOREQ_OP_COUNT, then this operation is pending completion, and the integer represents to which group of operations the ioreq belongs. Each group is represented by one master, and the integer in request_set is an index into masters to find the master data. - if it is REQSET_EMPTY, the ioreq op is inactive and available to be started - finally, if request_set[op] is REQSET_DONE, then the operation is complete and unavailable to be started again request_data[op] is the request data as supplied by the initiator of a request, and is valid iff request_set[op] <= GRPC_IOREQ_OP_COUNT. The set fields are as per the request type specified by op. Finally, one element of masters is set per active _set_ of ioreq operations. It describes work left outstanding, result status, and what work to perform upon operation completion. As one ioreq of each op type can be active at once, by convention we choose the first element of the group to be the master -- ie the master of in-progress operation op is masters[request_set[op]]. This allows constant time allocation and a strong upper bound of a count of masters to be calculated. */ gpr_uint8 request_set[GRPC_IOREQ_OP_COUNT]; grpc_ioreq_data request_data[GRPC_IOREQ_OP_COUNT]; gpr_uint32 request_flags[GRPC_IOREQ_OP_COUNT]; reqinfo_master masters[GRPC_IOREQ_OP_COUNT]; /* Dynamic array of ioreq's that have completed: the count of elements is queued in num_completed_requests. This list is built up under lock(), and flushed entirely during unlock(). We know the upper bound of the number of elements as we can only have one ioreq of each type active at once. */ completed_request completed_requests[GRPC_IOREQ_OP_COUNT]; /* Incoming buffer of messages */ grpc_byte_buffer_queue incoming_queue; /* Buffered read metadata waiting to be returned to the application. Element 0 is initial metadata, element 1 is trailing metadata. */ grpc_metadata_array buffered_metadata[2]; /* All metadata received - unreffed at once at the end of the call */ grpc_mdelem **owned_metadata; size_t owned_metadata_count; size_t owned_metadata_capacity; /* Received call statuses from various sources */ received_status status[STATUS_SOURCE_COUNT]; /* Compression algorithm for the call */ grpc_compression_algorithm compression_algorithm; /* Supported encodings (compression algorithms), a bitset */ gpr_uint32 encodings_accepted_by_peer; /* Contexts for various subsystems (security, tracing, ...). */ grpc_call_context_element context[GRPC_CONTEXT_COUNT]; /* Deadline alarm - if have_alarm is non-zero */ grpc_alarm alarm; /* Call refcount - to keep the call alive during asynchronous operations */ gpr_refcount internal_refcount; grpc_linked_mdelem send_initial_metadata[MAX_SEND_INITIAL_METADATA_COUNT]; grpc_linked_mdelem status_link; grpc_linked_mdelem details_link; size_t send_initial_metadata_count; gpr_timespec send_deadline; grpc_stream_op_buffer send_ops; grpc_stream_op_buffer recv_ops; grpc_stream_state recv_state; gpr_slice_buffer incoming_message; gpr_uint32 incoming_message_length; gpr_uint32 incoming_message_flags; grpc_iomgr_closure destroy_closure; grpc_iomgr_closure on_done_recv; grpc_iomgr_closure on_done_send; grpc_iomgr_closure on_done_bind; /** completion events - for completion queue use */ grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS]; /** siblings: children of the same parent form a list, and this list is protected under parent->mu */ grpc_call *sibling_next; grpc_call *sibling_prev; }; #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1)) #define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1) #define CALL_ELEM_FROM_CALL(call, idx) \ grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx) #define CALL_FROM_TOP_ELEM(top_elem) \ CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem)) static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline); static void call_on_done_recv(void *call, int success); static void call_on_done_send(void *call, int success); static int fill_send_ops(grpc_call *call, grpc_transport_stream_op *op); static void execute_op(grpc_call *call, grpc_transport_stream_op *op); static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata); static void finish_read_ops(grpc_call *call); static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status, const char *description); static void finished_loose_op(void *call, int success); static void lock(grpc_call *call); static void unlock(grpc_call *call); grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *cq, const void *server_transport_data, grpc_mdelem **add_initial_metadata, size_t add_initial_metadata_count, gpr_timespec send_deadline) { size_t i; grpc_transport_stream_op initial_op; grpc_transport_stream_op *initial_op_ptr = NULL; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_call *call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); memset(call, 0, sizeof(grpc_call)); gpr_mu_init(&call->mu); gpr_mu_init(&call->completion_mu); call->channel = channel; call->cq = cq; if (cq != NULL) { GRPC_CQ_INTERNAL_REF(cq, "bind"); } call->parent = parent_call; call->is_client = server_transport_data == NULL; for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { call->request_set[i] = REQSET_EMPTY; } if (call->is_client) { call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE; call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE; } GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT); for (i = 0; i < add_initial_metadata_count; i++) { call->send_initial_metadata[i].md = add_initial_metadata[i]; } call->send_initial_metadata_count = add_initial_metadata_count; call->send_deadline = send_deadline; GRPC_CHANNEL_INTERNAL_REF(channel, "call"); call->metadata_context = grpc_channel_get_metadata_context(channel); grpc_sopb_init(&call->send_ops); grpc_sopb_init(&call->recv_ops); gpr_slice_buffer_init(&call->incoming_message); grpc_iomgr_closure_init(&call->on_done_recv, call_on_done_recv, call); grpc_iomgr_closure_init(&call->on_done_send, call_on_done_send, call); grpc_iomgr_closure_init(&call->on_done_bind, finished_loose_op, call); /* dropped in destroy and when READ_STATE_STREAM_CLOSED received */ gpr_ref_init(&call->internal_refcount, 2); /* server hack: start reads immediately so we can get initial metadata. TODO(ctiller): figure out a cleaner solution */ if (!call->is_client) { memset(&initial_op, 0, sizeof(initial_op)); initial_op.recv_ops = &call->recv_ops; initial_op.recv_state = &call->recv_state; initial_op.on_done_recv = &call->on_done_recv; initial_op.context = call->context; call->receiving = 1; GRPC_CALL_INTERNAL_REF(call, "receiving"); initial_op_ptr = &initial_op; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, CALL_STACK_FROM_CALL(call)); if (parent_call != NULL) { GRPC_CALL_INTERNAL_REF(parent_call, "child"); GPR_ASSERT(call->is_client); GPR_ASSERT(!parent_call->is_client); gpr_mu_lock(&parent_call->mu); if (propagation_mask & GRPC_PROPAGATE_DEADLINE) { send_deadline = gpr_time_min( gpr_convert_clock_type(send_deadline, parent_call->send_deadline.clock_type), parent_call->send_deadline); } /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with * GRPC_PROPAGATE_STATS_CONTEXT */ /* TODO(ctiller): This should change to use the appropriate census start_op * call. */ if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); grpc_call_context_set(call, GRPC_CONTEXT_TRACING, parent_call->context[GRPC_CONTEXT_TRACING].value, NULL); } else { GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); } if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) { call->cancellation_is_inherited = 1; } if (parent_call->first_child == NULL) { parent_call->first_child = call; call->sibling_next = call->sibling_prev = call; } else { call->sibling_next = parent_call->first_child; call->sibling_prev = parent_call->first_child->sibling_prev; call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = call; } gpr_mu_unlock(&parent_call->mu); } if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) != 0) { set_deadline_alarm(call, send_deadline); } return call; } void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq) { lock(call); call->cq = cq; if (cq) { GRPC_CQ_INTERNAL_REF(cq, "bind"); } unlock(call); } grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) { return call->cq; } static grpc_cq_completion *allocate_completion(grpc_call *call) { gpr_uint8 i; gpr_mu_lock(&call->completion_mu); for (i = 0; i < GPR_ARRAY_SIZE(call->completions); i++) { if (call->allocated_completions & (1u << i)) { continue; } call->allocated_completions |= 1u << i; gpr_mu_unlock(&call->completion_mu); return &call->completions[i]; } gpr_log(GPR_ERROR, "should never reach here"); abort(); } static void done_completion(void *call, grpc_cq_completion *completion) { grpc_call *c = call; gpr_mu_lock(&c->completion_mu); c->allocated_completions &= ~(1u << (completion - c->completions)); gpr_mu_unlock(&c->completion_mu); GRPC_CALL_INTERNAL_UNREF(c, "completion", 1); } #ifdef GRPC_CALL_REF_COUNT_DEBUG void grpc_call_internal_ref(grpc_call *c, const char *reason) { gpr_log(GPR_DEBUG, "CALL: ref %p %d -> %d [%s]", c, c->internal_refcount.count, c->internal_refcount.count + 1, reason); #else void grpc_call_internal_ref(grpc_call *c) { #endif gpr_ref(&c->internal_refcount); } static void destroy_call(void *call, int ignored_success) { size_t i; grpc_call *c = call; grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c)); GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call"); gpr_mu_destroy(&c->mu); gpr_mu_destroy(&c->completion_mu); for (i = 0; i < STATUS_SOURCE_COUNT; i++) { if (c->status[i].details) { GRPC_MDSTR_UNREF(c->status[i].details); } } for (i = 0; i < c->owned_metadata_count; i++) { GRPC_MDELEM_UNREF(c->owned_metadata[i]); } gpr_free(c->owned_metadata); for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) { gpr_free(c->buffered_metadata[i].metadata); } for (i = 0; i < c->send_initial_metadata_count; i++) { GRPC_MDELEM_UNREF(c->send_initial_metadata[i].md); } for (i = 0; i < GRPC_CONTEXT_COUNT; i++) { if (c->context[i].destroy) { c->context[i].destroy(c->context[i].value); } } grpc_sopb_destroy(&c->send_ops); grpc_sopb_destroy(&c->recv_ops); grpc_bbq_destroy(&c->incoming_queue); gpr_slice_buffer_destroy(&c->incoming_message); if (c->cq) { GRPC_CQ_INTERNAL_UNREF(c->cq, "bind"); } gpr_free(c); } #ifdef GRPC_CALL_REF_COUNT_DEBUG void grpc_call_internal_unref(grpc_call *c, const char *reason, int allow_immediate_deletion) { gpr_log(GPR_DEBUG, "CALL: unref %p %d -> %d [%s]", c, c->internal_refcount.count, c->internal_refcount.count - 1, reason); #else void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) { #endif if (gpr_unref(&c->internal_refcount)) { if (allow_immediate_deletion) { destroy_call(c, 1); } else { c->destroy_closure.cb = destroy_call; c->destroy_closure.cb_arg = c; grpc_iomgr_add_callback(&c->destroy_closure); } } } static void set_status_code(grpc_call *call, status_source source, gpr_uint32 status) { if (call->status[source].is_set) return; call->status[source].is_set = 1; call->status[source].code = status; call->error_status_set = status != GRPC_STATUS_OK; if (status != GRPC_STATUS_OK && !grpc_bbq_empty(&call->incoming_queue)) { grpc_bbq_flush(&call->incoming_queue); } } static void set_compression_algorithm(grpc_call *call, grpc_compression_algorithm algo) { call->compression_algorithm = algo; } grpc_compression_algorithm grpc_call_get_compression_algorithm( const grpc_call *call) { return call->compression_algorithm; } static void set_encodings_accepted_by_peer( grpc_call *call, const gpr_slice accept_encoding_slice) { size_t i; grpc_compression_algorithm algorithm; gpr_slice_buffer accept_encoding_parts; gpr_slice_buffer_init(&accept_encoding_parts); gpr_slice_split(accept_encoding_slice, ", ", &accept_encoding_parts); /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already * zeroes the whole grpc_call */ /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); for (i = 0; i < accept_encoding_parts.count; i++) { const gpr_slice *accept_encoding_entry_slice = &accept_encoding_parts.slices[i]; if (grpc_compression_algorithm_parse( (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice), GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); } else { char *accept_encoding_entry_str = gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); gpr_log(GPR_ERROR, "Invalid entry in accept encoding metadata: '%s'. Ignoring.", accept_encoding_entry_str); gpr_free(accept_encoding_entry_str); } } } gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) { return call->encodings_accepted_by_peer; } gpr_uint32 grpc_call_get_message_flags(const grpc_call *call) { return call->incoming_message_flags; } static void set_status_details(grpc_call *call, status_source source, grpc_mdstr *status) { if (call->status[source].details != NULL) { GRPC_MDSTR_UNREF(call->status[source].details); } call->status[source].details = status; } static int is_op_live(grpc_call *call, grpc_ioreq_op op) { gpr_uint8 set = call->request_set[op]; reqinfo_master *master; if (set >= GRPC_IOREQ_OP_COUNT) return 0; master = &call->masters[set]; return (master->complete_mask & (1u << op)) == 0; } static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); } static int need_more_data(grpc_call *call) { if (call->read_state == READ_STATE_STREAM_CLOSED) return 0; /* TODO(ctiller): this needs some serious cleanup */ return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) || (is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) && grpc_bbq_empty(&call->incoming_queue)) || is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) || is_op_live(call, GRPC_IOREQ_RECV_STATUS) || is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) || (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) && grpc_bbq_empty(&call->incoming_queue)) || (call->write_state == WRITE_STATE_INITIAL && !call->is_client) || (call->cancel_with_status != GRPC_STATUS_OK) || call->destroy_called; } static void unlock(grpc_call *call) { grpc_transport_stream_op op; completed_request completed_requests[GRPC_IOREQ_OP_COUNT]; int completing_requests = 0; int start_op = 0; int i; const gpr_uint32 MAX_RECV_PEEK_AHEAD = 65536; size_t buffered_bytes; int cancel_alarm = 0; memset(&op, 0, sizeof(op)); op.cancel_with_status = call->cancel_with_status; start_op = op.cancel_with_status != GRPC_STATUS_OK; call->cancel_with_status = GRPC_STATUS_OK; /* reset */ cancel_alarm = call->cancel_alarm; call->cancel_alarm = 0; if (!call->receiving && need_more_data(call)) { if (grpc_bbq_empty(&call->incoming_queue) && call->reading_message) { op.max_recv_bytes = call->incoming_message_length - call->incoming_message.length + MAX_RECV_PEEK_AHEAD; } else { buffered_bytes = grpc_bbq_bytes(&call->incoming_queue); if (buffered_bytes > MAX_RECV_PEEK_AHEAD) { op.max_recv_bytes = 0; } else { op.max_recv_bytes = MAX_RECV_PEEK_AHEAD - buffered_bytes; } } /* TODO(ctiller): 1024 is basically to cover a bug I don't understand yet */ if (op.max_recv_bytes > 1024) { op.recv_ops = &call->recv_ops; op.recv_state = &call->recv_state; op.on_done_recv = &call->on_done_recv; call->receiving = 1; GRPC_CALL_INTERNAL_REF(call, "receiving"); start_op = 1; } } if (!call->sending) { if (fill_send_ops(call, &op)) { call->sending = 1; GRPC_CALL_INTERNAL_REF(call, "sending"); start_op = 1; } } if (!call->bound_pollset && call->cq && (!call->is_client || start_op)) { call->bound_pollset = 1; op.bind_pollset = grpc_cq_pollset(call->cq); start_op = 1; } if (!call->completing && call->num_completed_requests != 0) { completing_requests = call->num_completed_requests; memcpy(completed_requests, call->completed_requests, sizeof(completed_requests)); call->num_completed_requests = 0; call->completing = 1; GRPC_CALL_INTERNAL_REF(call, "completing"); } gpr_mu_unlock(&call->mu); if (cancel_alarm) { grpc_alarm_cancel(&call->alarm); } if (start_op) { execute_op(call, &op); } if (completing_requests > 0) { for (i = 0; i < completing_requests; i++) { completed_requests[i].on_complete(call, completed_requests[i].success, completed_requests[i].user_data); } lock(call); call->completing = 0; unlock(call); GRPC_CALL_INTERNAL_UNREF(call, "completing", 0); } } static void get_final_status(grpc_call *call, grpc_ioreq_data out) { int i; for (i = 0; i < STATUS_SOURCE_COUNT; i++) { if (call->status[i].is_set) { out.recv_status.set_value(call->status[i].code, out.recv_status.user_data); return; } } if (call->is_client) { out.recv_status.set_value(GRPC_STATUS_UNKNOWN, out.recv_status.user_data); } else { out.recv_status.set_value(GRPC_STATUS_OK, out.recv_status.user_data); } } static void get_final_details(grpc_call *call, grpc_ioreq_data out) { int i; for (i = 0; i < STATUS_SOURCE_COUNT; i++) { if (call->status[i].is_set) { if (call->status[i].details) { gpr_slice details = call->status[i].details->slice; size_t len = GPR_SLICE_LENGTH(details); if (len + 1 > *out.recv_status_details.details_capacity) { *out.recv_status_details.details_capacity = GPR_MAX( len + 1, *out.recv_status_details.details_capacity * 3 / 2); *out.recv_status_details.details = gpr_realloc(*out.recv_status_details.details, *out.recv_status_details.details_capacity); } memcpy(*out.recv_status_details.details, GPR_SLICE_START_PTR(details), len); (*out.recv_status_details.details)[len] = 0; } else { goto no_details; } return; } } no_details: if (0 == *out.recv_status_details.details_capacity) { *out.recv_status_details.details_capacity = 8; *out.recv_status_details.details = gpr_malloc(*out.recv_status_details.details_capacity); } **out.recv_status_details.details = 0; } static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op, int success) { completed_request *cr; gpr_uint8 master_set = call->request_set[op]; reqinfo_master *master; size_t i; /* ioreq is live: we need to do something */ master = &call->masters[master_set]; master->complete_mask |= 1u << op; if (!success) { master->success = 0; } if (master->complete_mask == master->need_mask) { for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { if (call->request_set[i] != master_set) { continue; } call->request_set[i] = REQSET_DONE; switch ((grpc_ioreq_op)i) { case GRPC_IOREQ_RECV_MESSAGE: case GRPC_IOREQ_SEND_MESSAGE: call->request_set[i] = REQSET_EMPTY; if (!master->success) { call->write_state = WRITE_STATE_WRITE_CLOSED; } break; case GRPC_IOREQ_SEND_STATUS: if (call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details != NULL) { GRPC_MDSTR_UNREF( call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details); call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details = NULL; } break; case GRPC_IOREQ_RECV_CLOSE: case GRPC_IOREQ_SEND_INITIAL_METADATA: case GRPC_IOREQ_SEND_TRAILING_METADATA: case GRPC_IOREQ_SEND_CLOSE: break; case GRPC_IOREQ_RECV_STATUS: get_final_status(call, call->request_data[GRPC_IOREQ_RECV_STATUS]); break; case GRPC_IOREQ_RECV_STATUS_DETAILS: get_final_details(call, call->request_data[GRPC_IOREQ_RECV_STATUS_DETAILS]); break; case GRPC_IOREQ_RECV_INITIAL_METADATA: GPR_SWAP(grpc_metadata_array, call->buffered_metadata[0], *call->request_data[GRPC_IOREQ_RECV_INITIAL_METADATA] .recv_metadata); break; case GRPC_IOREQ_RECV_TRAILING_METADATA: GPR_SWAP(grpc_metadata_array, call->buffered_metadata[1], *call->request_data[GRPC_IOREQ_RECV_TRAILING_METADATA] .recv_metadata); break; case GRPC_IOREQ_OP_COUNT: abort(); break; } } cr = &call->completed_requests[call->num_completed_requests++]; cr->success = master->success; cr->on_complete = master->on_complete; cr->user_data = master->user_data; } } static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op, int success) { if (is_op_live(call, op)) { finish_live_ioreq_op(call, op, success); } } static void early_out_write_ops(grpc_call *call) { switch (call->write_state) { case WRITE_STATE_WRITE_CLOSED: finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, 0); finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, 0); finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, 0); finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, 1); /* fallthrough */ case WRITE_STATE_STARTED: finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, 0); /* fallthrough */ case WRITE_STATE_INITIAL: /* do nothing */ break; } } static void call_on_done_send(void *pc, int success) { grpc_call *call = pc; lock(call); if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, success); call->write_state = WRITE_STATE_STARTED; } if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, success); } if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_CLOSE)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, success); finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, success); finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, 1); call->write_state = WRITE_STATE_WRITE_CLOSED; } if (!success) { call->write_state = WRITE_STATE_WRITE_CLOSED; early_out_write_ops(call); } call->send_ops.nops = 0; call->last_send_contains = 0; call->sending = 0; unlock(call); GRPC_CALL_INTERNAL_UNREF(call, "sending", 0); } static void finish_message(grpc_call *call) { if (call->error_status_set == 0) { /* TODO(ctiller): this could be a lot faster if coded directly */ grpc_byte_buffer *byte_buffer; /* some aliases for readability */ gpr_slice *slices = call->incoming_message.slices; const size_t nslices = call->incoming_message.count; if ((call->incoming_message_flags & GRPC_WRITE_INTERNAL_COMPRESS) && (call->compression_algorithm > GRPC_COMPRESS_NONE)) { byte_buffer = grpc_raw_compressed_byte_buffer_create( slices, nslices, call->compression_algorithm); } else { byte_buffer = grpc_raw_byte_buffer_create(slices, nslices); } grpc_bbq_push(&call->incoming_queue, byte_buffer); } gpr_slice_buffer_reset_and_unref(&call->incoming_message); GPR_ASSERT(call->incoming_message.count == 0); call->reading_message = 0; } static int begin_message(grpc_call *call, grpc_begin_message msg) { /* can't begin a message when we're still reading a message */ if (call->reading_message) { char *message = NULL; gpr_asprintf( &message, "Message terminated early; read %d bytes, expected %d", (int)call->incoming_message.length, (int)call->incoming_message_length); cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message); gpr_free(message); return 0; } /* sanity check: if message flags indicate a compressed message, the * compression level should already be present in the call, as parsed off its * corresponding metadata. */ if ((msg.flags & GRPC_WRITE_INTERNAL_COMPRESS) && (call->compression_algorithm == GRPC_COMPRESS_NONE)) { char *message = NULL; char *alg_name; if (!grpc_compression_algorithm_name(call->compression_algorithm, &alg_name)) { /* This shouldn't happen, other than due to data corruption */ alg_name = ""; } gpr_asprintf(&message, "Invalid compression algorithm (%s) for compressed message.", alg_name); cancel_with_status(call, GRPC_STATUS_INTERNAL, message); gpr_free(message); return 0; } /* stash away parameters, and prepare for incoming slices */ if (msg.length > grpc_channel_get_max_message_length(call->channel)) { char *message = NULL; gpr_asprintf( &message, "Maximum message length of %d exceeded by a message of length %d", grpc_channel_get_max_message_length(call->channel), msg.length); cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message); gpr_free(message); return 0; } else if (msg.length > 0) { call->reading_message = 1; call->incoming_message_length = msg.length; call->incoming_message_flags = msg.flags; return 1; } else { finish_message(call); return 1; } } static int add_slice_to_message(grpc_call *call, gpr_slice slice) { if (GPR_SLICE_LENGTH(slice) == 0) { gpr_slice_unref(slice); return 1; } /* we have to be reading a message to know what to do here */ if (!call->reading_message) { cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, "Received payload data while not reading a message"); return 0; } /* append the slice to the incoming buffer */ gpr_slice_buffer_add(&call->incoming_message, slice); if (call->incoming_message.length > call->incoming_message_length) { /* if we got too many bytes, complain */ char *message = NULL; gpr_asprintf( &message, "Receiving message overflow; read %d bytes, expected %d", (int)call->incoming_message.length, (int)call->incoming_message_length); cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message); gpr_free(message); return 0; } else if (call->incoming_message.length == call->incoming_message_length) { finish_message(call); return 1; } else { return 1; } } static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; grpc_call *child_call; grpc_call *next_child_call; size_t i; GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0); lock(call); call->receiving = 0; if (success) { for (i = 0; success && i < call->recv_ops.nops; i++) { grpc_stream_op *op = &call->recv_ops.ops[i]; switch (op->type) { case GRPC_NO_OP: break; case GRPC_OP_METADATA: recv_metadata(call, &op->data.metadata); break; case GRPC_OP_BEGIN_MESSAGE: success = begin_message(call, op->data.begin_message); break; case GRPC_OP_SLICE: success = add_slice_to_message(call, op->data.slice); break; } } if (!success) { grpc_stream_ops_unref_owned_objects(&call->recv_ops.ops[i], call->recv_ops.nops - i); } if (call->recv_state == GRPC_STREAM_RECV_CLOSED) { GPR_ASSERT(call->read_state <= READ_STATE_READ_CLOSED); call->read_state = READ_STATE_READ_CLOSED; } if (call->recv_state == GRPC_STREAM_CLOSED) { GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED); call->read_state = READ_STATE_STREAM_CLOSED; call->cancel_alarm |= call->have_alarm; /* propagate cancellation to any interested children */ child_call = call->first_child; if (child_call != NULL) { do { next_child_call = child_call->sibling_next; if (child_call->cancellation_is_inherited) { GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel"); grpc_call_cancel(child_call, NULL); GRPC_CALL_INTERNAL_UNREF(child_call, "propagate_cancel", 0); } child_call = next_child_call; } while (child_call != call->first_child); } GRPC_CALL_INTERNAL_UNREF(call, "closed", 0); } finish_read_ops(call); } else { finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, 0); } call->recv_ops.nops = 0; unlock(call); GRPC_CALL_INTERNAL_UNREF(call, "receiving", 0); GRPC_TIMER_END(GRPC_PTAG_CALL_ON_DONE_RECV, 0); } static int prepare_application_metadata(grpc_call *call, size_t count, grpc_metadata *metadata) { size_t i; for (i = 0; i < count; i++) { grpc_metadata *md = &metadata[i]; grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1]; grpc_metadata *prev_md = (i == 0) ? NULL : &metadata[i - 1]; grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data; GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data)); l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key, (const gpr_uint8 *)md->value, md->value_length, 1); if (!grpc_mdstr_is_legal_header(l->md->key)) { gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s", grpc_mdstr_as_c_string(l->md->key)); return 0; } else if (!grpc_mdstr_is_bin_suffixed(l->md->key) && !grpc_mdstr_is_legal_nonbin_header(l->md->value)) { gpr_log(GPR_ERROR, "attempt to send invalid metadata value"); return 0; } l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL; l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL; } return 1; } static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, grpc_metadata *metadata) { grpc_mdelem_list out; if (count == 0) { out.head = out.tail = NULL; return out; } out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data); out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data); return out; } /* Copy the contents of a byte buffer into stream ops */ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, grpc_stream_op_buffer *sopb) { size_t i; switch (byte_buffer->type) { case GRPC_BB_RAW: for (i = 0; i < byte_buffer->data.raw.slice_buffer.count; i++) { gpr_slice slice = byte_buffer->data.raw.slice_buffer.slices[i]; gpr_slice_ref(slice); grpc_sopb_add_slice(sopb, slice); } break; } } static int fill_send_ops(grpc_call *call, grpc_transport_stream_op *op) { grpc_ioreq_data data; gpr_uint32 flags; grpc_metadata_batch mdb; size_t i; GPR_ASSERT(op->send_ops == NULL); switch (call->write_state) { case WRITE_STATE_INITIAL: if (!is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) { break; } data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA]; mdb.list = chain_metadata_from_app(call, data.send_metadata.count, data.send_metadata.metadata); mdb.garbage.head = mdb.garbage.tail = NULL; mdb.deadline = call->send_deadline; for (i = 0; i < call->send_initial_metadata_count; i++) { grpc_metadata_batch_link_head(&mdb, &call->send_initial_metadata[i]); } grpc_sopb_add_metadata(&call->send_ops, mdb); op->send_ops = &call->send_ops; call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA; call->send_initial_metadata_count = 0; /* fall through intended */ case WRITE_STATE_STARTED: if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { data = call->request_data[GRPC_IOREQ_SEND_MESSAGE]; flags = call->request_flags[GRPC_IOREQ_SEND_MESSAGE]; grpc_sopb_add_begin_message( &call->send_ops, grpc_byte_buffer_length(data.send_message), flags); copy_byte_buffer_to_stream_ops(data.send_message, &call->send_ops); op->send_ops = &call->send_ops; call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE; } if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) { op->is_last_send = 1; op->send_ops = &call->send_ops; call->last_send_contains |= 1 << GRPC_IOREQ_SEND_CLOSE; if (!call->is_client) { /* send trailing metadata */ data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA]; mdb.list = chain_metadata_from_app(call, data.send_metadata.count, data.send_metadata.metadata); mdb.garbage.head = mdb.garbage.tail = NULL; mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME); /* send status */ /* TODO(ctiller): cache common status values */ data = call->request_data[GRPC_IOREQ_SEND_STATUS]; grpc_metadata_batch_add_tail( &mdb, &call->status_link, grpc_channel_get_reffed_status_elem(call->channel, data.send_status.code)); if (data.send_status.details) { grpc_metadata_batch_add_tail( &mdb, &call->details_link, grpc_mdelem_from_metadata_strings( call->metadata_context, GRPC_MDSTR_REF( grpc_channel_get_message_string(call->channel)), data.send_status.details)); call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details = NULL; } grpc_sopb_add_metadata(&call->send_ops, mdb); } } break; case WRITE_STATE_WRITE_CLOSED: break; } if (op->send_ops) { op->on_done_send = &call->on_done_send; } return op->send_ops != NULL; } static grpc_call_error start_ioreq_error(grpc_call *call, gpr_uint32 mutated_ops, grpc_call_error ret) { size_t i; for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { if (mutated_ops & (1u << i)) { call->request_set[i] = REQSET_EMPTY; } } return ret; } static void finish_read_ops(grpc_call *call) { int empty; if (is_op_live(call, GRPC_IOREQ_RECV_MESSAGE)) { empty = (NULL == (*call->request_data[GRPC_IOREQ_RECV_MESSAGE].recv_message = grpc_bbq_pop(&call->incoming_queue))); if (!empty) { finish_live_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, 1); empty = grpc_bbq_empty(&call->incoming_queue); } } else { empty = grpc_bbq_empty(&call->incoming_queue); } switch (call->read_state) { case READ_STATE_STREAM_CLOSED: if (empty && !call->have_alarm) { finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, 1); } /* fallthrough */ case READ_STATE_READ_CLOSED: if (empty) { finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, 1); } finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, 1); finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, 1); finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, 1); /* fallthrough */ case READ_STATE_GOT_INITIAL_METADATA: finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, 1); /* fallthrough */ case READ_STATE_INITIAL: /* do nothing */ break; } } static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, grpc_ioreq_completion_func completion, void *user_data) { size_t i; gpr_uint32 have_ops = 0; grpc_ioreq_op op; reqinfo_master *master; grpc_ioreq_data data; gpr_uint8 set; if (nreqs == 0) { return GRPC_CALL_OK; } set = reqs[0].op; for (i = 0; i < nreqs; i++) { op = reqs[i].op; if (call->request_set[op] < GRPC_IOREQ_OP_COUNT) { return start_ioreq_error(call, have_ops, GRPC_CALL_ERROR_TOO_MANY_OPERATIONS); } else if (call->request_set[op] == REQSET_DONE) { return start_ioreq_error(call, have_ops, GRPC_CALL_ERROR_ALREADY_INVOKED); } data = reqs[i].data; if (op == GRPC_IOREQ_SEND_INITIAL_METADATA || op == GRPC_IOREQ_SEND_TRAILING_METADATA) { if (!prepare_application_metadata(call, data.send_metadata.count, data.send_metadata.metadata)) { return start_ioreq_error(call, have_ops, GRPC_CALL_ERROR_INVALID_METADATA); } } if (op == GRPC_IOREQ_SEND_STATUS) { set_status_code(call, STATUS_FROM_SERVER_STATUS, reqs[i].data.send_status.code); if (reqs[i].data.send_status.details) { set_status_details(call, STATUS_FROM_SERVER_STATUS, GRPC_MDSTR_REF(reqs[i].data.send_status.details)); } } have_ops |= 1u << op; call->request_data[op] = data; call->request_flags[op] = reqs[i].flags; call->request_set[op] = set; } master = &call->masters[set]; master->success = 1; master->need_mask = have_ops; master->complete_mask = 0; master->on_complete = completion; master->user_data = user_data; finish_read_ops(call); early_out_write_ops(call); return GRPC_CALL_OK; } grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, grpc_ioreq_completion_func on_complete, void *user_data) { grpc_call_error err; lock(call); err = start_ioreq(call, reqs, nreqs, on_complete, user_data); unlock(call); return err; } void grpc_call_destroy(grpc_call *c) { int cancel; grpc_call *parent = c->parent; if (parent) { gpr_mu_lock(&parent->mu); if (c == parent->first_child) { parent->first_child = c->sibling_next; if (c == parent->first_child) { parent->first_child = NULL; } c->sibling_prev->sibling_next = c->sibling_next; c->sibling_next->sibling_prev = c->sibling_prev; } gpr_mu_unlock(&parent->mu); GRPC_CALL_INTERNAL_UNREF(parent, "child", 1); } lock(c); GPR_ASSERT(!c->destroy_called); c->destroy_called = 1; c->cancel_alarm |= c->have_alarm; cancel = c->read_state != READ_STATE_STREAM_CLOSED; unlock(c); if (cancel) grpc_call_cancel(c, NULL); GRPC_CALL_INTERNAL_UNREF(c, "destroy", 1); } grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) { GPR_ASSERT(!reserved); return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled", NULL); } grpc_call_error grpc_call_cancel_with_status(grpc_call *c, grpc_status_code status, const char *description, void *reserved) { grpc_call_error r; (void)reserved; lock(c); r = cancel_with_status(c, status, description); unlock(c); return r; } static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status, const char *description) { grpc_mdstr *details = description ? grpc_mdstr_from_string(c->metadata_context, description, 0) : NULL; GPR_ASSERT(status != GRPC_STATUS_OK); set_status_code(c, STATUS_FROM_API_OVERRIDE, status); set_status_details(c, STATUS_FROM_API_OVERRIDE, details); c->cancel_with_status = status; return GRPC_CALL_OK; } static void finished_loose_op(void *call, int success_ignored) { GRPC_CALL_INTERNAL_UNREF(call, "loose-op", 0); } typedef struct { grpc_call *call; grpc_iomgr_closure closure; } finished_loose_op_allocated_args; static void finished_loose_op_allocated(void *alloc, int success) { finished_loose_op_allocated_args *args = alloc; finished_loose_op(args->call, success); gpr_free(args); } static void execute_op(grpc_call *call, grpc_transport_stream_op *op) { grpc_call_element *elem; GPR_ASSERT(op->on_consumed == NULL); if (op->cancel_with_status != GRPC_STATUS_OK || op->bind_pollset) { GRPC_CALL_INTERNAL_REF(call, "loose-op"); if (op->bind_pollset) { op->on_consumed = &call->on_done_bind; } else { finished_loose_op_allocated_args *args = gpr_malloc(sizeof(*args)); args->call = call; grpc_iomgr_closure_init(&args->closure, finished_loose_op_allocated, args); op->on_consumed = &args->closure; } } elem = CALL_ELEM_FROM_CALL(call, 0); op->context = call->context; elem->filter->start_transport_stream_op(elem, op); } char *grpc_call_get_peer(grpc_call *call) { grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0); return elem->filter->get_peer(elem); } grpc_call *grpc_call_from_top_element(grpc_call_element *elem) { return CALL_FROM_TOP_ELEM(elem); } static void call_alarm(void *arg, int success) { grpc_call *call = arg; lock(call); call->have_alarm = 0; if (success) { cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED, "Deadline Exceeded"); } finish_read_ops(call); unlock(call); GRPC_CALL_INTERNAL_UNREF(call, "alarm", 1); } static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { if (call->have_alarm) { gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice"); assert(0); return; } GRPC_CALL_INTERNAL_REF(call, "alarm"); call->have_alarm = 1; call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); grpc_alarm_init(&call->alarm, call->send_deadline, call_alarm, call, gpr_now(GPR_CLOCK_MONOTONIC)); } /* we offset status by a small amount when storing it into transport metadata as metadata cannot store a 0 value (which is used as OK for grpc_status_codes */ #define STATUS_OFFSET 1 static void destroy_status(void *ignored) {} static gpr_uint32 decode_status(grpc_mdelem *md) { gpr_uint32 status; void *user_data = grpc_mdelem_get_user_data(md, destroy_status); if (user_data) { status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET; } else { if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value), GPR_SLICE_LENGTH(md->value->slice), &status)) { status = GRPC_STATUS_UNKNOWN; /* could not parse status code */ } grpc_mdelem_set_user_data(md, destroy_status, (void *)(gpr_intptr)(status + STATUS_OFFSET)); } return status; } /* just as for status above, we need to offset: metadata userdata can't hold a * zero (null), which in this case is used to signal no compression */ #define COMPRESS_OFFSET 1 static void destroy_compression(void *ignored) {} static gpr_uint32 decode_compression(grpc_mdelem *md) { grpc_compression_algorithm algorithm; void *user_data = grpc_mdelem_get_user_data(md, destroy_compression); if (user_data) { algorithm = ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET; } else { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str); assert(0); } grpc_mdelem_set_user_data( md, destroy_compression, (void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET)); } return algorithm; } static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) { grpc_linked_mdelem *l; grpc_metadata_array *dest; grpc_metadata *mdusr; int is_trailing; grpc_mdctx *mdctx = call->metadata_context; is_trailing = call->read_state >= READ_STATE_GOT_INITIAL_METADATA; for (l = md->list.head; l != NULL; l = l->next) { grpc_mdelem *md = l->md; grpc_mdstr *key = md->key; if (key == grpc_channel_get_status_string(call->channel)) { set_status_code(call, STATUS_FROM_WIRE, decode_status(md)); } else if (key == grpc_channel_get_message_string(call->channel)) { set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(md->value)); } else if (key == grpc_channel_get_compression_algorithm_string(call->channel)) { set_compression_algorithm(call, decode_compression(md)); } else if (key == grpc_channel_get_encodings_accepted_by_peer_string( call->channel)) { set_encodings_accepted_by_peer(call, md->value->slice); } else { dest = &call->buffered_metadata[is_trailing]; if (dest->count == dest->capacity) { dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2); dest->metadata = gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity); } mdusr = &dest->metadata[dest->count++]; mdusr->key = grpc_mdstr_as_c_string(md->key); mdusr->value = grpc_mdstr_as_c_string(md->value); mdusr->value_length = GPR_SLICE_LENGTH(md->value->slice); if (call->owned_metadata_count == call->owned_metadata_capacity) { call->owned_metadata_capacity = GPR_MAX(call->owned_metadata_capacity + 8, call->owned_metadata_capacity * 2); call->owned_metadata = gpr_realloc(call->owned_metadata, sizeof(grpc_mdelem *) * call->owned_metadata_capacity); } call->owned_metadata[call->owned_metadata_count++] = md; l->md = 0; } } if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) != 0 && !call->is_client) { set_deadline_alarm(call, md->deadline); } if (!is_trailing) { call->read_state = READ_STATE_GOT_INITIAL_METADATA; } grpc_mdctx_lock(mdctx); for (l = md->list.head; l; l = l->next) { if (l->md) GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md); } for (l = md->garbage.head; l; l = l->next) { GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md); } grpc_mdctx_unlock(mdctx); } grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { return CALL_STACK_FROM_CALL(call); } /* * BATCH API IMPLEMENTATION */ static void set_status_value_directly(grpc_status_code status, void *dest) { *(grpc_status_code *)dest = status; } static void set_cancelled_value(grpc_status_code status, void *dest) { *(grpc_status_code *)dest = (status != GRPC_STATUS_OK); } static void finish_batch(grpc_call *call, int success, void *tag) { grpc_cq_end_op(call->cq, tag, success, done_completion, call, allocate_completion(call)); } static void finish_batch_with_close(grpc_call *call, int success, void *tag) { grpc_cq_end_op(call->cq, tag, 1, done_completion, call, allocate_completion(call)); } static int are_write_flags_valid(gpr_uint32 flags) { /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */ const gpr_uint32 allowed_write_positions = (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK); const gpr_uint32 invalid_positions = ~allowed_write_positions; return !(flags & invalid_positions); } grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, size_t nops, void *tag, void *reserved) { grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT]; size_t in; size_t out; const grpc_op *op; grpc_ioreq *req; void (*finish_func)(grpc_call *, int, void *) = finish_batch; if (reserved != NULL) return GRPC_CALL_ERROR; GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag); if (nops == 0) { grpc_cq_begin_op(call->cq); GRPC_CALL_INTERNAL_REF(call, "completion"); grpc_cq_end_op(call->cq, tag, 1, done_completion, call, allocate_completion(call)); return GRPC_CALL_OK; } /* rewrite batch ops into ioreq ops */ for (in = 0, out = 0; in < nops; in++) { op = &ops[in]; if (op->reserved != NULL) return GRPC_CALL_ERROR; switch (op->op) { case GRPC_OP_SEND_INITIAL_METADATA: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_INITIAL_METADATA; req->data.send_metadata.count = op->data.send_initial_metadata.count; req->data.send_metadata.metadata = op->data.send_initial_metadata.metadata; req->flags = op->flags; break; case GRPC_OP_SEND_MESSAGE: if (!are_write_flags_valid(op->flags)) { return GRPC_CALL_ERROR_INVALID_FLAGS; } if (op->data.send_message == NULL) { return GRPC_CALL_ERROR_INVALID_MESSAGE; } req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_MESSAGE; req->data.send_message = op->data.send_message; req->flags = op->flags; break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; if (!call->is_client) { return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_CLOSE; req->flags = op->flags; break; case GRPC_OP_SEND_STATUS_FROM_SERVER: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; if (call->is_client) { return GRPC_CALL_ERROR_NOT_ON_CLIENT; } req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_TRAILING_METADATA; req->flags = op->flags; req->data.send_metadata.count = op->data.send_status_from_server.trailing_metadata_count; req->data.send_metadata.metadata = op->data.send_status_from_server.trailing_metadata; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_STATUS; req->data.send_status.code = op->data.send_status_from_server.status; req->data.send_status.details = op->data.send_status_from_server.status_details != NULL ? grpc_mdstr_from_string( call->metadata_context, op->data.send_status_from_server.status_details, 0) : NULL; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_CLOSE; break; case GRPC_OP_RECV_INITIAL_METADATA: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; if (!call->is_client) { return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_INITIAL_METADATA; req->data.recv_metadata = op->data.recv_initial_metadata; req->data.recv_metadata->count = 0; req->flags = op->flags; break; case GRPC_OP_RECV_MESSAGE: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_MESSAGE; req->data.recv_message = op->data.recv_message; req->flags = op->flags; break; case GRPC_OP_RECV_STATUS_ON_CLIENT: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; if (!call->is_client) { return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS; req->flags = op->flags; req->data.recv_status.set_value = set_status_value_directly; req->data.recv_status.user_data = op->data.recv_status_on_client.status; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS_DETAILS; req->data.recv_status_details.details = op->data.recv_status_on_client.status_details; req->data.recv_status_details.details_capacity = op->data.recv_status_on_client.status_details_capacity; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_TRAILING_METADATA; req->data.recv_metadata = op->data.recv_status_on_client.trailing_metadata; req->data.recv_metadata->count = 0; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_CLOSE; finish_func = finish_batch_with_close; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS; req->flags = op->flags; req->data.recv_status.set_value = set_cancelled_value; req->data.recv_status.user_data = op->data.recv_close_on_server.cancelled; req = &reqs[out++]; if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_CLOSE; finish_func = finish_batch_with_close; break; } } GRPC_CALL_INTERNAL_REF(call, "completion"); grpc_cq_begin_op(call->cq); return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func, tag); } void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value, void (*destroy)(void *value)) { if (call->context[elem].destroy) { call->context[elem].destroy(call->context[elem].value); } call->context[elem].value = value; call->context[elem].destroy = destroy; } void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) { return call->context[elem].value; } gpr_uint8 grpc_call_is_client(grpc_call *call) { return call->is_client; } grpc-0.11.1/src/core/surface/init.h0000644000175000017500000000335112600663151017204 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_INIT_H #define GRPC_INTERNAL_CORE_SURFACE_INIT_H void grpc_security_pre_init(void); int grpc_is_initialized(void); #endif /* GRPC_INTERNAL_CORE_SURFACE_INIT_H */ grpc-0.11.1/src/core/surface/init_secure.c0000644000175000017500000000360012600663151020542 0ustar apollockapollock/* * * 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/surface/init.h" #include "src/core/debug/trace.h" #include "src/core/security/secure_endpoint.h" #include "src/core/tsi/transport_security_interface.h" void grpc_security_pre_init(void) { grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint); grpc_register_tracer("transport_security", &tsi_tracing_enabled); } grpc-0.11.1/src/core/surface/server.h0000644000175000017500000000575212600663151017556 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_SERVER_H #define GRPC_INTERNAL_CORE_SURFACE_SERVER_H #include "src/core/channel/channel_stack.h" #include #include "src/core/transport/transport.h" /* Create a server */ grpc_server *grpc_server_create_from_filters( const grpc_channel_filter **filters, size_t filter_count, const grpc_channel_args *args); /* Add a listener to the server: when the server starts, it will call start, and when it shuts down, it will call destroy */ void grpc_server_add_listener(grpc_server *server, void *listener, void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets, size_t npollsets), void (*destroy)(grpc_server *server, void *arg)); void grpc_server_listener_destroy_done(void *server); /* Setup a transport - creates a channel stack, binds the transport to the server */ void grpc_server_setup_transport(grpc_server *server, grpc_transport *transport, grpc_channel_filter const **extra_filters, size_t num_extra_filters, grpc_mdctx *mdctx, const grpc_channel_args *args); const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); int grpc_server_has_open_connections(grpc_server *server); #endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */ grpc-0.11.1/src/core/surface/completion_queue.h0000644000175000017500000000700112600663151021612 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H #define GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H /* Internal API for completion queues */ #include "src/core/iomgr/pollset.h" #include typedef struct grpc_cq_completion { /** user supplied tag */ void *tag; /** done callback - called when this queue element is no longer needed by the completion queue */ void (*done)(void *done_arg, struct grpc_cq_completion *c); void *done_arg; /** next pointer; low bit is used to indicate success or not */ gpr_uintptr next; } grpc_cq_completion; #ifdef GRPC_CQ_REF_COUNT_DEBUG void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, const char *file, int line); void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, const char *file, int line); #define GRPC_CQ_INTERNAL_REF(cc, reason) \ grpc_cq_internal_ref(cc, reason, __FILE__, __LINE__) #define GRPC_CQ_INTERNAL_UNREF(cc, reason) \ grpc_cq_internal_unref(cc, reason, __FILE__, __LINE__) #else void grpc_cq_internal_ref(grpc_completion_queue *cc); void grpc_cq_internal_unref(grpc_completion_queue *cc); #define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc) #define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc) #endif /* Flag that an operation is beginning: the completion channel will not finish shutdown until a corrensponding grpc_cq_end_* call is made */ void grpc_cq_begin_op(grpc_completion_queue *cc); /* Queue a GRPC_OP_COMPLETED operation */ void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success, void (*done)(void *done_arg, grpc_cq_completion *storage), void *done_arg, grpc_cq_completion *storage); grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); void grpc_cq_mark_server_cq(grpc_completion_queue *cc); int grpc_cq_is_server_cq(grpc_completion_queue *cc); #endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */ grpc-0.11.1/src/core/surface/byte_buffer_reader.c0000644000175000017500000000753312600663151022060 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include "src/core/compression/message_compress.h" static int is_compressed(grpc_byte_buffer *buffer) { switch (buffer->type) { case GRPC_BB_RAW: if (buffer->data.raw.compression == GRPC_COMPRESS_NONE) { return 0 /* GPR_FALSE */; } break; } return 1 /* GPR_TRUE */; } void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, grpc_byte_buffer *buffer) { gpr_slice_buffer decompressed_slices_buffer; reader->buffer_in = buffer; switch (reader->buffer_in->type) { case GRPC_BB_RAW: gpr_slice_buffer_init(&decompressed_slices_buffer); if (is_compressed(reader->buffer_in)) { grpc_msg_decompress(reader->buffer_in->data.raw.compression, &reader->buffer_in->data.raw.slice_buffer, &decompressed_slices_buffer); reader->buffer_out = grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices, decompressed_slices_buffer.count); gpr_slice_buffer_destroy(&decompressed_slices_buffer); } else { /* not compressed, use the input buffer as output */ reader->buffer_out = reader->buffer_in; } reader->current.index = 0; break; } } void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) { switch (reader->buffer_in->type) { case GRPC_BB_RAW: /* keeping the same if-else structure as in the init function */ if (is_compressed(reader->buffer_in)) { grpc_byte_buffer_destroy(reader->buffer_out); } break; } } int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, gpr_slice *slice) { switch (reader->buffer_in->type) { case GRPC_BB_RAW: { gpr_slice_buffer *slice_buffer; slice_buffer = &reader->buffer_out->data.raw.slice_buffer; if (reader->current.index < slice_buffer->count) { *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]); reader->current.index += 1; return 1; } break; } } return 0; } grpc-0.11.1/src/core/surface/call_details.c0000644000175000017500000000345512600663151020661 0ustar apollockapollock/* * * 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 #include #include void grpc_call_details_init(grpc_call_details *cd) { memset(cd, 0, sizeof(*cd)); } void grpc_call_details_destroy(grpc_call_details *cd) { gpr_free(cd->method); gpr_free(cd->host); } grpc-0.11.1/src/core/surface/server_create.c0000644000175000017500000000373612600663151021074 0ustar apollockapollock/* * * 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 #include "src/core/surface/completion_queue.h" #include "src/core/surface/server.h" #include "src/core/channel/compress_filter.h" grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { const grpc_channel_filter *filters[] = {&grpc_compress_filter}; (void)reserved; return grpc_server_create_from_filters(filters, GPR_ARRAY_SIZE(filters), args); } grpc-0.11.1/src/core/surface/completion_queue.c0000644000175000017500000002653112600663151021616 0ustar apollockapollock/* * * 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/surface/completion_queue.h" #include #include #include "src/core/iomgr/pollset.h" #include "src/core/support/string.h" #include "src/core/surface/call.h" #include "src/core/surface/event_string.h" #include "src/core/surface/surface_trace.h" #include #include #include typedef struct { grpc_pollset_worker *worker; void *tag; } plucker; /* Completion queue structure */ struct grpc_completion_queue { /** completed events */ grpc_cq_completion completed_head; grpc_cq_completion *completed_tail; /** Number of pending events (+1 if we're not shutdown) */ gpr_refcount pending_events; /** Once owning_refs drops to zero, we will destroy the cq */ gpr_refcount owning_refs; /** the set of low level i/o things that concern this cq */ grpc_pollset pollset; /** 0 initially, 1 once we've begun shutting down */ int shutdown; int shutdown_called; int is_server_cq; int num_pluckers; plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS]; }; grpc_completion_queue *grpc_completion_queue_create(void *reserved) { grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue)); GPR_ASSERT(!reserved); memset(cc, 0, sizeof(*cc)); /* Initial ref is dropped by grpc_completion_queue_shutdown */ gpr_ref_init(&cc->pending_events, 1); /* One for destroy(), one for pollset_shutdown */ gpr_ref_init(&cc->owning_refs, 2); grpc_pollset_init(&cc->pollset); cc->completed_tail = &cc->completed_head; cc->completed_head.next = (gpr_uintptr)cc->completed_tail; return cc; } #ifdef GRPC_CQ_REF_COUNT_DEBUG void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cc, (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason); #else void grpc_cq_internal_ref(grpc_completion_queue *cc) { #endif gpr_ref(&cc->owning_refs); } static void on_pollset_destroy_done(void *arg) { grpc_completion_queue *cc = arg; GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy"); } #ifdef GRPC_CQ_REF_COUNT_DEBUG void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc, (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason); #else void grpc_cq_internal_unref(grpc_completion_queue *cc) { #endif if (gpr_unref(&cc->owning_refs)) { GPR_ASSERT(cc->completed_head.next == (gpr_uintptr)&cc->completed_head); grpc_pollset_destroy(&cc->pollset); gpr_free(cc); } } void grpc_cq_begin_op(grpc_completion_queue *cc) { #ifndef NDEBUG gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); GPR_ASSERT(!cc->shutdown_called); gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); #endif gpr_ref(&cc->pending_events); } /* Signal the end of an operation - if this is the last waiting-to-be-queued event, then enter shutdown mode */ /* Queue a GRPC_OP_COMPLETED operation */ void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success, void (*done)(void *done_arg, grpc_cq_completion *storage), void *done_arg, grpc_cq_completion *storage) { int shutdown; int i; grpc_pollset_worker *pluck_worker; storage->tag = tag; storage->done = done; storage->done_arg = done_arg; storage->next = ((gpr_uintptr)&cc->completed_head) | ((gpr_uintptr)(success != 0)); gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); shutdown = gpr_unref(&cc->pending_events); if (!shutdown) { cc->completed_tail->next = ((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next); cc->completed_tail = storage; pluck_worker = NULL; for (i = 0; i < cc->num_pluckers; i++) { if (cc->pluckers[i].tag == tag) { pluck_worker = cc->pluckers[i].worker; break; } } grpc_pollset_kick(&cc->pollset, pluck_worker); gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); } else { cc->completed_tail->next = ((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next); cc->completed_tail = storage; GPR_ASSERT(!cc->shutdown); GPR_ASSERT(cc->shutdown_called); cc->shutdown = 1; gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc); } } grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, gpr_timespec deadline, void *reserved) { grpc_event ret; grpc_pollset_worker worker; int first_loop = 1; gpr_timespec now; GPR_ASSERT(!reserved); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); GRPC_CQ_INTERNAL_REF(cc, "next"); gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); for (;;) { if (cc->completed_tail != &cc->completed_head) { grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; cc->completed_head.next = c->next & ~(gpr_uintptr)1; if (c == cc->completed_tail) { cc->completed_tail = &cc->completed_head; } gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); ret.type = GRPC_OP_COMPLETE; ret.success = c->next & 1u; ret.tag = c->tag; c->done(c->done_arg, c); break; } if (cc->shutdown) { gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_SHUTDOWN; break; } now = gpr_now(GPR_CLOCK_MONOTONIC); if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; break; } first_loop = 0; grpc_pollset_work(&cc->pollset, &worker, now, deadline); } GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); GRPC_CQ_INTERNAL_UNREF(cc, "next"); return ret; } static int add_plucker(grpc_completion_queue *cc, void *tag, grpc_pollset_worker *worker) { if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { return 0; } cc->pluckers[cc->num_pluckers].tag = tag; cc->pluckers[cc->num_pluckers].worker = worker; cc->num_pluckers++; return 1; } static void del_plucker(grpc_completion_queue *cc, void *tag, grpc_pollset_worker *worker) { int i; for (i = 0; i < cc->num_pluckers; i++) { if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) { cc->num_pluckers--; GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]); return; } } gpr_log(GPR_ERROR, "should never reach here"); abort(); } grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, gpr_timespec deadline, void *reserved) { grpc_event ret; grpc_cq_completion *c; grpc_cq_completion *prev; grpc_pollset_worker worker; gpr_timespec now; int first_loop = 1; GPR_ASSERT(!reserved); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); GRPC_CQ_INTERNAL_REF(cc, "pluck"); gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); for (;;) { prev = &cc->completed_head; while ((c = (grpc_cq_completion *)(prev->next & ~(gpr_uintptr)1)) != &cc->completed_head) { if (c->tag == tag) { prev->next = (prev->next & (gpr_uintptr)1) | (c->next & ~(gpr_uintptr)1); if (c == cc->completed_tail) { cc->completed_tail = prev; } gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); ret.type = GRPC_OP_COMPLETE; ret.success = c->next & 1u; ret.tag = c->tag; c->done(c->done_arg, c); goto done; } prev = c; } if (cc->shutdown) { gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_SHUTDOWN; break; } if (!add_plucker(cc, tag, &worker)) { gpr_log(GPR_DEBUG, "Too many outstanding grpc_completion_queue_pluck calls: maximum " "is %d", GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); memset(&ret, 0, sizeof(ret)); /* TODO(ctiller): should we use a different result here */ ret.type = GRPC_QUEUE_TIMEOUT; break; } now = gpr_now(GPR_CLOCK_MONOTONIC); if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { del_plucker(cc, tag, &worker); gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; break; } first_loop = 0; grpc_pollset_work(&cc->pollset, &worker, now, deadline); del_plucker(cc, tag, &worker); } done: GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); GRPC_CQ_INTERNAL_UNREF(cc, "pluck"); return ret; } /* Shutdown simply drops a ref that we reserved at creation time; if we drop to zero here, then enter shutdown mode and wake up any waiters */ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) { gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); if (cc->shutdown_called) { gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); return; } cc->shutdown_called = 1; gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); if (gpr_unref(&cc->pending_events)) { gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); GPR_ASSERT(!cc->shutdown); cc->shutdown = 1; gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc); } } void grpc_completion_queue_destroy(grpc_completion_queue *cc) { grpc_completion_queue_shutdown(cc); GRPC_CQ_INTERNAL_UNREF(cc, "destroy"); } grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { return &cc->pollset; } void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; } grpc-0.11.1/src/core/surface/channel_create.c0000644000175000017500000001516312600663151021173 0ustar apollockapollock/* * * 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 #include #include #include #include "src/core/census/grpc_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/channel/client_channel.h" #include "src/core/channel/compress_filter.h" #include "src/core/channel/http_client_filter.h" #include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/surface/channel.h" #include "src/core/transport/chttp2_transport.h" typedef struct { grpc_connector base; gpr_refcount refs; grpc_iomgr_closure *notify; grpc_connect_in_args args; grpc_connect_out_args *result; } connector; static void connector_ref(grpc_connector *con) { connector *c = (connector *)con; gpr_ref(&c->refs); } static void connector_unref(grpc_connector *con) { connector *c = (connector *)con; if (gpr_unref(&c->refs)) { gpr_free(c); } } static void connected(void *arg, grpc_endpoint *tcp) { connector *c = arg; grpc_iomgr_closure *notify; if (tcp != NULL) { c->result->transport = grpc_create_chttp2_transport( c->args.channel_args, tcp, c->args.metadata_context, 1); grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0); GPR_ASSERT(c->result->transport); c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *)); c->result->filters[0] = &grpc_http_client_filter; c->result->num_filters = 1; } else { memset(c->result, 0, sizeof(*c->result)); } notify = c->notify; c->notify = NULL; grpc_iomgr_add_callback(notify); } static void connector_connect(grpc_connector *con, const grpc_connect_in_args *args, grpc_connect_out_args *result, grpc_iomgr_closure *notify) { connector *c = (connector *)con; GPR_ASSERT(c->notify == NULL); GPR_ASSERT(notify->cb); c->notify = notify; c->args = *args; c->result = result; grpc_tcp_client_connect(connected, c, args->interested_parties, args->addr, args->addr_len, args->deadline); } static const grpc_connector_vtable connector_vtable = { connector_ref, connector_unref, connector_connect}; typedef struct { grpc_subchannel_factory base; gpr_refcount refs; grpc_mdctx *mdctx; grpc_channel_args *merge_args; grpc_channel *master; } subchannel_factory; static void subchannel_factory_ref(grpc_subchannel_factory *scf) { subchannel_factory *f = (subchannel_factory *)scf; gpr_ref(&f->refs); } static void subchannel_factory_unref(grpc_subchannel_factory *scf) { subchannel_factory *f = (subchannel_factory *)scf; if (gpr_unref(&f->refs)) { GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory"); grpc_channel_args_destroy(f->merge_args); grpc_mdctx_unref(f->mdctx); gpr_free(f); } } static grpc_subchannel *subchannel_factory_create_subchannel( grpc_subchannel_factory *scf, grpc_subchannel_args *args) { subchannel_factory *f = (subchannel_factory *)scf; connector *c = gpr_malloc(sizeof(*c)); grpc_channel_args *final_args = grpc_channel_args_merge(args->args, f->merge_args); grpc_subchannel *s; memset(c, 0, sizeof(*c)); c->base.vtable = &connector_vtable; gpr_ref_init(&c->refs, 1); args->mdctx = f->mdctx; args->args = final_args; args->master = f->master; s = grpc_subchannel_create(&c->base, args); grpc_connector_unref(&c->base); grpc_channel_args_destroy(final_args); return s; } static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { subchannel_factory_ref, subchannel_factory_unref, subchannel_factory_create_subchannel}; /* Create a client channel: Asynchronously: - resolve target - connect to it (trying alternatives as presented) - perform handshakes */ grpc_channel *grpc_insecure_channel_create(const char *target, const grpc_channel_args *args, void *reserved) { grpc_channel *channel = NULL; #define MAX_FILTERS 3 const grpc_channel_filter *filters[MAX_FILTERS]; grpc_resolver *resolver; subchannel_factory *f; grpc_mdctx *mdctx = grpc_mdctx_create(); int n = 0; GPR_ASSERT(!reserved); if (grpc_channel_args_is_census_enabled(args)) { filters[n++] = &grpc_client_census_filter; } filters[n++] = &grpc_compress_filter; filters[n++] = &grpc_client_channel_filter; GPR_ASSERT(n <= MAX_FILTERS); channel = grpc_channel_create_from_filters(target, filters, n, args, mdctx, 1); f = gpr_malloc(sizeof(*f)); f->base.vtable = &subchannel_factory_vtable; gpr_ref_init(&f->refs, 1); grpc_mdctx_ref(mdctx); f->mdctx = mdctx; f->merge_args = grpc_channel_args_copy(args); f->master = channel; GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory"); resolver = grpc_resolver_create(target, &f->base); if (!resolver) { return NULL; } grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel), resolver); GRPC_RESOLVER_UNREF(resolver, "create"); grpc_subchannel_factory_unref(&f->base); return channel; } grpc-0.11.1/src/core/surface/channel.c0000644000175000017500000003371612600663151017654 0ustar apollockapollock/* * * 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/surface/channel.h" #include #include #include #include #include #include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/string.h" #include "src/core/surface/call.h" #include "src/core/surface/init.h" /** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS. * Avoids needing to take a metadata context lock for sending status * if the status code is <= NUM_CACHED_STATUS_ELEMS. * Sized to allow the most commonly used codes to fit in * (OK, Cancelled, Unknown). */ #define NUM_CACHED_STATUS_ELEMS 3 typedef struct registered_call { grpc_mdelem *path; grpc_mdelem *authority; struct registered_call *next; } registered_call; struct grpc_channel { int is_client; gpr_refcount refs; gpr_uint32 max_message_length; grpc_mdctx *metadata_context; /** mdstr for the grpc-status key */ grpc_mdstr *grpc_status_string; grpc_mdstr *grpc_compression_algorithm_string; grpc_mdstr *grpc_encodings_accepted_by_peer_string; grpc_mdstr *grpc_message_string; grpc_mdstr *path_string; grpc_mdstr *authority_string; grpc_mdelem *default_authority; /** mdelem for grpc-status: 0 thru grpc-status: 2 */ grpc_mdelem *grpc_status_elem[NUM_CACHED_STATUS_ELEMS]; gpr_mu registered_call_mu; registered_call *registered_calls; grpc_iomgr_closure destroy_closure; char *target; }; #define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) #define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \ (((grpc_channel *)(channel_stack)) - 1) #define CHANNEL_FROM_TOP_ELEM(top_elem) \ CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem)) /* the protobuf library will (by default) start warning at 100megs */ #define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024) grpc_channel *grpc_channel_create_from_filters( const char *target, const grpc_channel_filter **filters, size_t num_filters, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) { size_t i; size_t size = sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters); grpc_channel *channel = gpr_malloc(size); memset(channel, 0, sizeof(*channel)); channel->target = gpr_strdup(target); GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); channel->is_client = is_client; /* decremented by grpc_channel_destroy */ gpr_ref_init(&channel->refs, 1); channel->metadata_context = mdctx; channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0); channel->grpc_compression_algorithm_string = grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); channel->grpc_encodings_accepted_by_peer_string = grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0); channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0); for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) { char buf[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(i, buf); channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings( mdctx, GRPC_MDSTR_REF(channel->grpc_status_string), grpc_mdstr_from_string(mdctx, buf, 0)); } channel->path_string = grpc_mdstr_from_string(mdctx, ":path", 0); channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority", 0); gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; if (args) { for (i = 0; i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { if (args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", GRPC_ARG_MAX_MESSAGE_LENGTH); } else if (args->args[i].value.integer < 0) { gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", GRPC_ARG_MAX_MESSAGE_LENGTH); } else { channel->max_message_length = args->args[i].value.integer; } } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s: must be an string", GRPC_ARG_DEFAULT_AUTHORITY); } else { if (channel->default_authority) { /* setting this takes precedence over anything else */ GRPC_MDELEM_UNREF(channel->default_authority); } channel->default_authority = grpc_mdelem_from_strings( mdctx, ":authority", args->args[i].value.string); } } else if (0 == strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s: must be an string", GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); } else { if (channel->default_authority) { /* other ways of setting this (notably ssl) take precedence */ gpr_log(GPR_ERROR, "%s: default host already set some other way", GRPC_ARG_DEFAULT_AUTHORITY); } else { channel->default_authority = grpc_mdelem_from_strings( mdctx, ":authority", args->args[i].value.string); } } } } } if (channel->is_client && channel->default_authority == NULL && target != NULL) { char *default_authority = grpc_get_default_authority(target); if (default_authority) { channel->default_authority = grpc_mdelem_from_strings( channel->metadata_context, ":authority", default_authority); } gpr_free(default_authority); } grpc_channel_stack_init(filters, num_filters, channel, args, channel->metadata_context, CHANNEL_STACK_FROM_CHANNEL(channel)); return channel; } char *grpc_channel_get_target(grpc_channel *channel) { return gpr_strdup(channel->target); } static grpc_call *grpc_channel_create_call_internal( grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *cq, grpc_mdelem *path_mdelem, grpc_mdelem *authority_mdelem, gpr_timespec deadline) { grpc_mdelem *send_metadata[2]; int num_metadata = 0; GPR_ASSERT(channel->is_client); send_metadata[num_metadata++] = path_mdelem; if (authority_mdelem != NULL) { send_metadata[num_metadata++] = authority_mdelem; } else if (channel->default_authority != NULL) { send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority); } return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL, send_metadata, num_metadata, deadline); } grpc_call *grpc_channel_create_call(grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *cq, const char *method, const char *host, gpr_timespec deadline, void *reserved) { GPR_ASSERT(!reserved); return grpc_channel_create_call_internal( channel, parent_call, propagation_mask, cq, grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->path_string), grpc_mdstr_from_string(channel->metadata_context, method, 0)), host ? grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string), grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL, deadline); } void *grpc_channel_register_call(grpc_channel *channel, const char *method, const char *host, void *reserved) { registered_call *rc = gpr_malloc(sizeof(registered_call)); GPR_ASSERT(!reserved); rc->path = grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->path_string), grpc_mdstr_from_string(channel->metadata_context, method, 0)); rc->authority = host ? grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string), grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL; gpr_mu_lock(&channel->registered_call_mu); rc->next = channel->registered_calls; channel->registered_calls = rc; gpr_mu_unlock(&channel->registered_call_mu); return rc; } grpc_call *grpc_channel_create_registered_call( grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *completion_queue, void *registered_call_handle, gpr_timespec deadline, void *reserved) { registered_call *rc = registered_call_handle; GPR_ASSERT(!reserved); return grpc_channel_create_call_internal( channel, parent_call, propagation_mask, completion_queue, GRPC_MDELEM_REF(rc->path), rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline); } #ifdef GRPC_CHANNEL_REF_COUNT_DEBUG void grpc_channel_internal_ref(grpc_channel *c, const char *reason) { gpr_log(GPR_DEBUG, "CHANNEL: ref %p %d -> %d [%s]", c, c->refs.count, c->refs.count + 1, reason); #else void grpc_channel_internal_ref(grpc_channel *c) { #endif gpr_ref(&c->refs); } static void destroy_channel(void *p, int ok) { grpc_channel *channel = p; size_t i; grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel)); for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) { GRPC_MDELEM_UNREF(channel->grpc_status_elem[i]); } GRPC_MDSTR_UNREF(channel->grpc_status_string); GRPC_MDSTR_UNREF(channel->grpc_compression_algorithm_string); GRPC_MDSTR_UNREF(channel->grpc_encodings_accepted_by_peer_string); GRPC_MDSTR_UNREF(channel->grpc_message_string); GRPC_MDSTR_UNREF(channel->path_string); GRPC_MDSTR_UNREF(channel->authority_string); while (channel->registered_calls) { registered_call *rc = channel->registered_calls; channel->registered_calls = rc->next; GRPC_MDELEM_UNREF(rc->path); if (rc->authority) { GRPC_MDELEM_UNREF(rc->authority); } gpr_free(rc); } if (channel->default_authority != NULL) { GRPC_MDELEM_UNREF(channel->default_authority); } grpc_mdctx_unref(channel->metadata_context); gpr_mu_destroy(&channel->registered_call_mu); gpr_free(channel->target); gpr_free(channel); } #ifdef GRPC_CHANNEL_REF_COUNT_DEBUG void grpc_channel_internal_unref(grpc_channel *channel, const char *reason) { gpr_log(GPR_DEBUG, "CHANNEL: unref %p %d -> %d [%s]", channel, channel->refs.count, channel->refs.count - 1, reason); #else void grpc_channel_internal_unref(grpc_channel *channel) { #endif if (gpr_unref(&channel->refs)) { channel->destroy_closure.cb = destroy_channel; channel->destroy_closure.cb_arg = channel; grpc_iomgr_add_callback(&channel->destroy_closure); } } void grpc_channel_destroy(grpc_channel *channel) { grpc_transport_op op; grpc_channel_element *elem; memset(&op, 0, sizeof(op)); op.disconnect = 1; elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); elem->filter->start_transport_op(elem, &op); GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel"); } grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) { return CHANNEL_STACK_FROM_CHANNEL(channel); } grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel) { return channel->metadata_context; } grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) { return channel->grpc_status_string; } grpc_mdstr *grpc_channel_get_compression_algorithm_string( grpc_channel *channel) { return channel->grpc_compression_algorithm_string; } grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string( grpc_channel *channel) { return channel->grpc_encodings_accepted_by_peer_string; } grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) { return GRPC_MDELEM_REF(channel->grpc_status_elem[i]); } else { char tmp[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(i, tmp); return grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string), grpc_mdstr_from_string(channel->metadata_context, tmp, 0)); } } grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) { return channel->grpc_message_string; } gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel) { return channel->max_message_length; } grpc-0.11.1/src/core/surface/server.c0000644000175000017500000012434512600663151017551 0ustar apollockapollock/* * * 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/surface/server.h" #include #include #include #include #include #include #include "src/core/census/grpc_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/channel/connected_channel.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/stack_lockfree.h" #include "src/core/support/string.h" #include "src/core/surface/call.h" #include "src/core/surface/channel.h" #include "src/core/surface/completion_queue.h" #include "src/core/surface/init.h" #include "src/core/transport/metadata.h" typedef struct listener { void *arg; void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets, size_t pollset_count); void (*destroy)(grpc_server *server, void *arg); struct listener *next; } listener; typedef struct call_data call_data; typedef struct channel_data channel_data; typedef struct registered_method registered_method; typedef struct { call_data *next; call_data *prev; } call_link; typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type; typedef struct requested_call { requested_call_type type; void *tag; grpc_server *server; grpc_completion_queue *cq_bound_to_call; grpc_completion_queue *cq_for_notification; grpc_call **call; grpc_cq_completion completion; union { struct { grpc_call_details *details; grpc_metadata_array *initial_metadata; } batch; struct { registered_method *registered_method; gpr_timespec *deadline; grpc_metadata_array *initial_metadata; grpc_byte_buffer **optional_payload; } registered; } data; } requested_call; typedef struct channel_registered_method { registered_method *server_registered_method; grpc_mdstr *method; grpc_mdstr *host; } channel_registered_method; struct channel_data { grpc_server *server; grpc_connectivity_state connectivity_state; grpc_channel *channel; grpc_mdstr *path_key; grpc_mdstr *authority_key; /* linked list of all channels on a server */ channel_data *next; channel_data *prev; channel_registered_method *registered_methods; gpr_uint32 registered_method_slots; gpr_uint32 registered_method_max_probes; grpc_iomgr_closure finish_destroy_channel_closure; grpc_iomgr_closure channel_connectivity_changed; }; typedef struct shutdown_tag { void *tag; grpc_completion_queue *cq; grpc_cq_completion completion; } shutdown_tag; typedef enum { /* waiting for metadata */ NOT_STARTED, /* inital metadata read, not flow controlled in yet */ PENDING, /* flow controlled in, on completion queue */ ACTIVATED, /* cancelled before being queued */ ZOMBIED } call_state; typedef struct request_matcher request_matcher; struct call_data { grpc_call *call; /** protects state */ gpr_mu mu_state; /** the current state of a call - see call_state */ call_state state; grpc_mdstr *path; grpc_mdstr *host; gpr_timespec deadline; int got_initial_metadata; grpc_completion_queue *cq_new; grpc_stream_op_buffer *recv_ops; grpc_stream_state *recv_state; grpc_iomgr_closure *on_done_recv; grpc_iomgr_closure server_on_recv; grpc_iomgr_closure kill_zombie_closure; call_data *pending_next; }; struct request_matcher { call_data *pending_head; call_data *pending_tail; gpr_stack_lockfree *requests; }; struct registered_method { char *method; char *host; request_matcher request_matcher; registered_method *next; }; typedef struct { grpc_channel **channels; size_t num_channels; } channel_broadcaster; struct grpc_server { size_t channel_filter_count; const grpc_channel_filter **channel_filters; grpc_channel_args *channel_args; grpc_completion_queue **cqs; grpc_pollset **pollsets; size_t cq_count; /* The two following mutexes control access to server-state mu_global controls access to non-call-related state (e.g., channel state) mu_call controls access to call-related state (e.g., the call lists) If they are ever required to be nested, you must lock mu_global before mu_call. This is currently used in shutdown processing (grpc_server_shutdown_and_notify and maybe_finish_shutdown) */ gpr_mu mu_global; /* mutex for server and channel state */ gpr_mu mu_call; /* mutex for call-specific state */ registered_method *registered_methods; request_matcher unregistered_request_matcher; /** free list of available requested_calls indices */ gpr_stack_lockfree *request_freelist; /** requested call backing data */ requested_call *requested_calls; int max_requested_calls; gpr_atm shutdown_flag; gpr_uint8 shutdown_published; size_t num_shutdown_tags; shutdown_tag *shutdown_tags; channel_data root_channel_data; listener *listeners; int listeners_destroyed; gpr_refcount internal_refcount; /** when did we print the last shutdown progress message */ gpr_timespec last_shutdown_message_time; }; #define SERVER_FROM_CALL_ELEM(elem) \ (((channel_data *)(elem)->channel_data)->server) static void begin_call(grpc_server *server, call_data *calld, requested_call *rc); static void fail_call(grpc_server *server, requested_call *rc); /* Before calling maybe_finish_shutdown, we must hold mu_global and not hold mu_call */ static void maybe_finish_shutdown(grpc_server *server); /* * channel broadcaster */ /* assumes server locked */ static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) { channel_data *c; size_t count = 0; for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { count++; } cb->num_channels = count; cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels); count = 0; for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { cb->channels[count++] = c->channel; GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast"); } } struct shutdown_cleanup_args { grpc_iomgr_closure closure; gpr_slice slice; }; static void shutdown_cleanup(void *arg, int iomgr_status_ignored) { struct shutdown_cleanup_args *a = arg; gpr_slice_unref(a->slice); gpr_free(a); } static void send_shutdown(grpc_channel *channel, int send_goaway, int send_disconnect) { grpc_transport_op op; struct shutdown_cleanup_args *sc; grpc_channel_element *elem; memset(&op, 0, sizeof(op)); op.send_goaway = send_goaway; sc = gpr_malloc(sizeof(*sc)); sc->slice = gpr_slice_from_copied_string("Server shutdown"); op.goaway_message = &sc->slice; op.goaway_status = GRPC_STATUS_OK; op.disconnect = send_disconnect; grpc_iomgr_closure_init(&sc->closure, shutdown_cleanup, sc); op.on_consumed = &sc->closure; elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); elem->filter->start_transport_op(elem, &op); } static void channel_broadcaster_shutdown(channel_broadcaster *cb, int send_goaway, int force_disconnect) { size_t i; for (i = 0; i < cb->num_channels; i++) { send_shutdown(cb->channels[i], send_goaway, force_disconnect); GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast"); } gpr_free(cb->channels); } /* * request_matcher */ static void request_matcher_init(request_matcher *request_matcher, int entries) { memset(request_matcher, 0, sizeof(*request_matcher)); request_matcher->requests = gpr_stack_lockfree_create(entries); } static void request_matcher_destroy(request_matcher *request_matcher) { GPR_ASSERT(gpr_stack_lockfree_pop(request_matcher->requests) == -1); gpr_stack_lockfree_destroy(request_matcher->requests); } static void kill_zombie(void *elem, int success) { grpc_call_destroy(grpc_call_from_top_element(elem)); } static void request_matcher_zombify_all_pending_calls( request_matcher *request_matcher) { while (request_matcher->pending_head) { call_data *calld = request_matcher->pending_head; request_matcher->pending_head = calld->pending_next; gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init( &calld->kill_zombie_closure, kill_zombie, grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); grpc_iomgr_add_callback(&calld->kill_zombie_closure); } } static void request_matcher_kill_requests(grpc_server *server, request_matcher *rm) { int request_id; while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) { fail_call(server, &server->requested_calls[request_id]); } } /* * server proper */ static void server_ref(grpc_server *server) { gpr_ref(&server->internal_refcount); } static void server_delete(grpc_server *server) { registered_method *rm; size_t i; grpc_channel_args_destroy(server->channel_args); gpr_mu_destroy(&server->mu_global); gpr_mu_destroy(&server->mu_call); gpr_free(server->channel_filters); while ((rm = server->registered_methods) != NULL) { server->registered_methods = rm->next; request_matcher_destroy(&rm->request_matcher); gpr_free(rm->method); gpr_free(rm->host); gpr_free(rm); } for (i = 0; i < server->cq_count; i++) { GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server"); } request_matcher_destroy(&server->unregistered_request_matcher); gpr_stack_lockfree_destroy(server->request_freelist); gpr_free(server->cqs); gpr_free(server->pollsets); gpr_free(server->shutdown_tags); gpr_free(server->requested_calls); gpr_free(server); } static void server_unref(grpc_server *server) { if (gpr_unref(&server->internal_refcount)) { server_delete(server); } } static int is_channel_orphaned(channel_data *chand) { return chand->next == chand; } static void orphan_channel(channel_data *chand) { chand->next->prev = chand->prev; chand->prev->next = chand->next; chand->next = chand->prev = chand; } static void finish_destroy_channel(void *cd, int success) { channel_data *chand = cd; grpc_server *server = chand->server; GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server"); server_unref(server); } static void destroy_channel(channel_data *chand) { if (is_channel_orphaned(chand)) return; GPR_ASSERT(chand->server != NULL); orphan_channel(chand); server_ref(chand->server); maybe_finish_shutdown(chand->server); chand->finish_destroy_channel_closure.cb = finish_destroy_channel; chand->finish_destroy_channel_closure.cb_arg = chand; grpc_iomgr_add_callback(&chand->finish_destroy_channel_closure); } static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem, request_matcher *request_matcher) { call_data *calld = elem->call_data; int request_id; if (gpr_atm_acq_load(&server->shutdown_flag)) { gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); grpc_iomgr_add_callback(&calld->kill_zombie_closure); return; } request_id = gpr_stack_lockfree_pop(request_matcher->requests); if (request_id == -1) { gpr_mu_lock(&server->mu_call); gpr_mu_lock(&calld->mu_state); calld->state = PENDING; gpr_mu_unlock(&calld->mu_state); if (request_matcher->pending_head == NULL) { request_matcher->pending_tail = request_matcher->pending_head = calld; } else { request_matcher->pending_tail->pending_next = calld; request_matcher->pending_tail = calld; } calld->pending_next = NULL; gpr_mu_unlock(&server->mu_call); } else { gpr_mu_lock(&calld->mu_state); calld->state = ACTIVATED; gpr_mu_unlock(&calld->mu_state); begin_call(server, calld, &server->requested_calls[request_id]); } } static void start_new_rpc(grpc_call_element *elem) { channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; grpc_server *server = chand->server; gpr_uint32 i; gpr_uint32 hash; channel_registered_method *rm; if (chand->registered_methods && calld->path && calld->host) { /* TODO(ctiller): unify these two searches */ /* check for an exact match with host */ hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash); for (i = 0; i <= chand->registered_method_max_probes; i++) { rm = &chand->registered_methods[(hash + i) % chand->registered_method_slots]; if (!rm) break; if (rm->host != calld->host) continue; if (rm->method != calld->path) continue; finish_start_new_rpc(server, elem, &rm->server_registered_method->request_matcher); return; } /* check for a wildcard method definition (no host set) */ hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash); for (i = 0; i <= chand->registered_method_max_probes; i++) { rm = &chand->registered_methods[(hash + i) % chand->registered_method_slots]; if (!rm) break; if (rm->host != NULL) continue; if (rm->method != calld->path) continue; finish_start_new_rpc(server, elem, &rm->server_registered_method->request_matcher); return; } } finish_start_new_rpc(server, elem, &server->unregistered_request_matcher); } static int num_listeners(grpc_server *server) { listener *l; int n = 0; for (l = server->listeners; l; l = l->next) { n++; } return n; } static void done_shutdown_event(void *server, grpc_cq_completion *completion) { server_unref(server); } static int num_channels(grpc_server *server) { channel_data *chand; int n = 0; for (chand = server->root_channel_data.next; chand != &server->root_channel_data; chand = chand->next) { n++; } return n; } static void kill_pending_work_locked(grpc_server *server) { registered_method *rm; request_matcher_kill_requests(server, &server->unregistered_request_matcher); request_matcher_zombify_all_pending_calls( &server->unregistered_request_matcher); for (rm = server->registered_methods; rm; rm = rm->next) { request_matcher_kill_requests(server, &rm->request_matcher); request_matcher_zombify_all_pending_calls(&rm->request_matcher); } } static void maybe_finish_shutdown(grpc_server *server) { size_t i; if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) { return; } kill_pending_work_locked(server); if (server->root_channel_data.next != &server->root_channel_data || server->listeners_destroyed < num_listeners(server)) { if (gpr_time_cmp(gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), server->last_shutdown_message_time), gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); gpr_log(GPR_DEBUG, "Waiting for %d channels and %d/%d listeners to be destroyed" " before shutting down server", num_channels(server), num_listeners(server) - server->listeners_destroyed, num_listeners(server)); } return; } server->shutdown_published = 1; for (i = 0; i < server->num_shutdown_tags; i++) { server_ref(server); grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag, 1, done_shutdown_event, server, &server->shutdown_tags[i].completion); } } static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; if (md->key == chand->path_key) { calld->path = GRPC_MDSTR_REF(md->value); return NULL; } else if (md->key == chand->authority_key) { calld->host = GRPC_MDSTR_REF(md->value); return NULL; } return md; } static void server_on_recv(void *ptr, int success) { grpc_call_element *elem = ptr; call_data *calld = elem->call_data; gpr_timespec op_deadline; if (success && !calld->got_initial_metadata) { size_t i; size_t nops = calld->recv_ops->nops; grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); op_deadline = op->data.metadata.deadline; if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) { calld->deadline = op->data.metadata.deadline; } if (calld->host && calld->path) { calld->got_initial_metadata = 1; start_new_rpc(elem); } break; } } switch (*calld->recv_state) { case GRPC_STREAM_OPEN: break; case GRPC_STREAM_SEND_CLOSED: break; case GRPC_STREAM_RECV_CLOSED: gpr_mu_lock(&calld->mu_state); if (calld->state == NOT_STARTED) { calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); grpc_iomgr_add_callback(&calld->kill_zombie_closure); } else { gpr_mu_unlock(&calld->mu_state); } break; case GRPC_STREAM_CLOSED: gpr_mu_lock(&calld->mu_state); if (calld->state == NOT_STARTED) { calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); grpc_iomgr_add_callback(&calld->kill_zombie_closure); } else if (calld->state == PENDING) { calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); /* zombied call will be destroyed when it's removed from the pending queue... later */ } else { gpr_mu_unlock(&calld->mu_state); } break; } calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } static void server_mutate_op(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; if (op->recv_ops) { /* substitute our callback for the higher callback */ calld->recv_ops = op->recv_ops; calld->recv_state = op->recv_state; calld->on_done_recv = op->on_done_recv; op->on_done_recv = &calld->server_on_recv; } } static void server_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); server_mutate_op(elem, op); grpc_call_next_op(elem, op); } static void accept_stream(void *cd, grpc_transport *transport, const void *transport_server_data) { channel_data *chand = cd; /* create a call */ grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data, NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC)); } static void channel_connectivity_changed(void *cd, int iomgr_status_ignored) { channel_data *chand = cd; grpc_server *server = chand->server; if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) { grpc_transport_op op; memset(&op, 0, sizeof(op)); op.on_connectivity_state_change = &chand->channel_connectivity_changed, op.connectivity_state = &chand->connectivity_state; grpc_channel_next_op(grpc_channel_stack_element( grpc_channel_get_channel_stack(chand->channel), 0), &op); } else { gpr_mu_lock(&server->mu_global); destroy_channel(chand); gpr_mu_unlock(&server->mu_global); GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "connectivity"); } } static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; memset(calld, 0, sizeof(call_data)); calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); calld->call = grpc_call_from_top_element(elem); gpr_mu_init(&calld->mu_state); grpc_iomgr_closure_init(&calld->server_on_recv, server_on_recv, elem); server_ref(chand->server); if (initial_op) server_mutate_op(elem, initial_op); } static void destroy_call_elem(grpc_call_element *elem) { channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; GPR_ASSERT(calld->state != PENDING); if (calld->host) { GRPC_MDSTR_UNREF(calld->host); } if (calld->path) { GRPC_MDSTR_UNREF(calld->path); } gpr_mu_destroy(&calld->mu_state); server_unref(chand->server); } static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *metadata_context, int is_first, int is_last) { channel_data *chand = elem->channel_data; GPR_ASSERT(is_first); GPR_ASSERT(!is_last); chand->server = NULL; chand->channel = NULL; chand->path_key = grpc_mdstr_from_string(metadata_context, ":path", 0); chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority", 0); chand->next = chand->prev = chand; chand->registered_methods = NULL; chand->connectivity_state = GRPC_CHANNEL_IDLE; grpc_iomgr_closure_init(&chand->channel_connectivity_changed, channel_connectivity_changed, chand); } static void destroy_channel_elem(grpc_channel_element *elem) { size_t i; channel_data *chand = elem->channel_data; if (chand->registered_methods) { for (i = 0; i < chand->registered_method_slots; i++) { if (chand->registered_methods[i].method) { GRPC_MDSTR_UNREF(chand->registered_methods[i].method); } if (chand->registered_methods[i].host) { GRPC_MDSTR_UNREF(chand->registered_methods[i].host); } } gpr_free(chand->registered_methods); } if (chand->server) { gpr_mu_lock(&chand->server->mu_global); chand->next->prev = chand->prev; chand->prev->next = chand->next; chand->next = chand->prev = chand; maybe_finish_shutdown(chand->server); gpr_mu_unlock(&chand->server->mu_global); GRPC_MDSTR_UNREF(chand->path_key); GRPC_MDSTR_UNREF(chand->authority_key); server_unref(chand->server); } } static const grpc_channel_filter server_surface_filter = { server_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "server", }; void grpc_server_register_completion_queue(grpc_server *server, grpc_completion_queue *cq, void *reserved) { size_t i, n; GPR_ASSERT(!reserved); for (i = 0; i < server->cq_count; i++) { if (server->cqs[i] == cq) return; } GRPC_CQ_INTERNAL_REF(cq, "server"); grpc_cq_mark_server_cq(cq); n = server->cq_count++; server->cqs = gpr_realloc(server->cqs, server->cq_count * sizeof(grpc_completion_queue *)); server->cqs[n] = cq; } grpc_server *grpc_server_create_from_filters( const grpc_channel_filter **filters, size_t filter_count, const grpc_channel_args *args) { size_t i; /* TODO(census): restore this once we finalize census filter etc. int census_enabled = grpc_channel_args_is_census_enabled(args); */ int census_enabled = 0; grpc_server *server = gpr_malloc(sizeof(grpc_server)); GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); memset(server, 0, sizeof(grpc_server)); gpr_mu_init(&server->mu_global); gpr_mu_init(&server->mu_call); /* decremented by grpc_server_destroy */ gpr_ref_init(&server->internal_refcount, 1); server->root_channel_data.next = server->root_channel_data.prev = &server->root_channel_data; /* TODO(ctiller): expose a channel_arg for this */ server->max_requested_calls = 32768; server->request_freelist = gpr_stack_lockfree_create(server->max_requested_calls); for (i = 0; i < (size_t)server->max_requested_calls; i++) { gpr_stack_lockfree_push(server->request_freelist, i); } request_matcher_init(&server->unregistered_request_matcher, server->max_requested_calls); server->requested_calls = gpr_malloc(server->max_requested_calls * sizeof(*server->requested_calls)); /* Server filter stack is: server_surface_filter - for making surface API calls grpc_server_census_filter (optional) - for stats collection and tracing {passed in filter stack} grpc_connected_channel_filter - for interfacing with transports */ server->channel_filter_count = filter_count + 1 + census_enabled; server->channel_filters = gpr_malloc(server->channel_filter_count * sizeof(grpc_channel_filter *)); server->channel_filters[0] = &server_surface_filter; if (census_enabled) { server->channel_filters[1] = &grpc_server_census_filter; } for (i = 0; i < filter_count; i++) { server->channel_filters[i + 1 + census_enabled] = filters[i]; } server->channel_args = grpc_channel_args_copy(args); return server; } static int streq(const char *a, const char *b) { if (a == NULL && b == NULL) return 1; if (a == NULL) return 0; if (b == NULL) return 0; return 0 == strcmp(a, b); } void *grpc_server_register_method(grpc_server *server, const char *method, const char *host) { registered_method *m; if (!method) { gpr_log(GPR_ERROR, "grpc_server_register_method method string cannot be NULL"); return NULL; } for (m = server->registered_methods; m; m = m->next) { if (streq(m->method, method) && streq(m->host, host)) { gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, host ? host : "*"); return NULL; } } m = gpr_malloc(sizeof(registered_method)); memset(m, 0, sizeof(*m)); request_matcher_init(&m->request_matcher, server->max_requested_calls); m->method = gpr_strdup(method); m->host = gpr_strdup(host); m->next = server->registered_methods; server->registered_methods = m; return m; } void grpc_server_start(grpc_server *server) { listener *l; size_t i; server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count); for (i = 0; i < server->cq_count; i++) { server->pollsets[i] = grpc_cq_pollset(server->cqs[i]); } for (l = server->listeners; l; l = l->next) { l->start(server, l->arg, server->pollsets, server->cq_count); } } void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport, grpc_channel_filter const **extra_filters, size_t num_extra_filters, grpc_mdctx *mdctx, const grpc_channel_args *args) { size_t num_filters = s->channel_filter_count + num_extra_filters + 1; grpc_channel_filter const **filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_filters); size_t i; size_t num_registered_methods; size_t alloc; registered_method *rm; channel_registered_method *crm; grpc_channel *channel; channel_data *chand; grpc_mdstr *host; grpc_mdstr *method; gpr_uint32 hash; gpr_uint32 slots; gpr_uint32 probes; gpr_uint32 max_probes = 0; grpc_transport_op op; for (i = 0; i < s->channel_filter_count; i++) { filters[i] = s->channel_filters[i]; } for (; i < s->channel_filter_count + num_extra_filters; i++) { filters[i] = extra_filters[i - s->channel_filter_count]; } filters[i] = &grpc_connected_channel_filter; for (i = 0; i < s->cq_count; i++) { memset(&op, 0, sizeof(op)); op.bind_pollset = grpc_cq_pollset(s->cqs[i]); grpc_transport_perform_op(transport, &op); } channel = grpc_channel_create_from_filters(NULL, filters, num_filters, args, mdctx, 0); chand = (channel_data *)grpc_channel_stack_element( grpc_channel_get_channel_stack(channel), 0) ->channel_data; chand->server = s; server_ref(s); chand->channel = channel; num_registered_methods = 0; for (rm = s->registered_methods; rm; rm = rm->next) { num_registered_methods++; } /* build a lookup table phrased in terms of mdstr's in this channels context to quickly find registered methods */ if (num_registered_methods > 0) { slots = 2 * num_registered_methods; alloc = sizeof(channel_registered_method) * slots; chand->registered_methods = gpr_malloc(alloc); memset(chand->registered_methods, 0, alloc); for (rm = s->registered_methods; rm; rm = rm->next) { host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host, 0) : NULL; method = grpc_mdstr_from_string(mdctx, rm->method, 0); hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash); for (probes = 0; chand->registered_methods[(hash + probes) % slots] .server_registered_method != NULL; probes++) ; if (probes > max_probes) max_probes = probes; crm = &chand->registered_methods[(hash + probes) % slots]; crm->server_registered_method = rm; crm->host = host; crm->method = method; } chand->registered_method_slots = slots; chand->registered_method_max_probes = max_probes; } grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel), transport); gpr_mu_lock(&s->mu_global); chand->next = &s->root_channel_data; chand->prev = chand->next->prev; chand->next->prev = chand->prev->next = chand; gpr_mu_unlock(&s->mu_global); gpr_free(filters); GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity"); memset(&op, 0, sizeof(op)); op.set_accept_stream = accept_stream; op.set_accept_stream_user_data = chand; op.on_connectivity_state_change = &chand->channel_connectivity_changed; op.connectivity_state = &chand->connectivity_state; op.disconnect = gpr_atm_acq_load(&s->shutdown_flag); grpc_transport_perform_op(transport, &op); } void done_published_shutdown(void *done_arg, grpc_cq_completion *storage) { (void) done_arg; gpr_free(storage); } void grpc_server_shutdown_and_notify(grpc_server *server, grpc_completion_queue *cq, void *tag) { listener *l; shutdown_tag *sdt; channel_broadcaster broadcaster; GRPC_SERVER_LOG_SHUTDOWN(GPR_INFO, server, cq, tag); /* lock, and gather up some stuff to do */ gpr_mu_lock(&server->mu_global); grpc_cq_begin_op(cq); if (server->shutdown_published) { grpc_cq_end_op(cq, tag, 1, done_published_shutdown, NULL, gpr_malloc(sizeof(grpc_cq_completion))); gpr_mu_unlock(&server->mu_global); return; } server->shutdown_tags = gpr_realloc(server->shutdown_tags, sizeof(shutdown_tag) * (server->num_shutdown_tags + 1)); sdt = &server->shutdown_tags[server->num_shutdown_tags++]; sdt->tag = tag; sdt->cq = cq; if (gpr_atm_acq_load(&server->shutdown_flag)) { gpr_mu_unlock(&server->mu_global); return; } server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); channel_broadcaster_init(server, &broadcaster); /* collect all unregistered then registered calls */ gpr_mu_lock(&server->mu_call); kill_pending_work_locked(server); gpr_mu_unlock(&server->mu_call); gpr_atm_rel_store(&server->shutdown_flag, 1); maybe_finish_shutdown(server); gpr_mu_unlock(&server->mu_global); /* Shutdown listeners */ for (l = server->listeners; l; l = l->next) { l->destroy(server, l->arg); } channel_broadcaster_shutdown(&broadcaster, 1, 0); } void grpc_server_listener_destroy_done(void *s) { grpc_server *server = s; gpr_mu_lock(&server->mu_global); server->listeners_destroyed++; maybe_finish_shutdown(server); gpr_mu_unlock(&server->mu_global); } void grpc_server_cancel_all_calls(grpc_server *server) { channel_broadcaster broadcaster; gpr_mu_lock(&server->mu_global); channel_broadcaster_init(server, &broadcaster); gpr_mu_unlock(&server->mu_global); channel_broadcaster_shutdown(&broadcaster, 0, 1); } void grpc_server_destroy(grpc_server *server) { listener *l; gpr_mu_lock(&server->mu_global); GPR_ASSERT(gpr_atm_acq_load(&server->shutdown_flag) || !server->listeners); GPR_ASSERT(server->listeners_destroyed == num_listeners(server)); while (server->listeners) { l = server->listeners; server->listeners = l->next; gpr_free(l); } gpr_mu_unlock(&server->mu_global); server_unref(server); } void grpc_server_add_listener(grpc_server *server, void *arg, void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets, size_t pollset_count), void (*destroy)(grpc_server *server, void *arg)) { listener *l = gpr_malloc(sizeof(listener)); l->arg = arg; l->start = start; l->destroy = destroy; l->next = server->listeners; server->listeners = l; } static grpc_call_error queue_call_request(grpc_server *server, requested_call *rc) { call_data *calld = NULL; request_matcher *request_matcher = NULL; int request_id; if (gpr_atm_acq_load(&server->shutdown_flag)) { fail_call(server, rc); return GRPC_CALL_OK; } request_id = gpr_stack_lockfree_pop(server->request_freelist); if (request_id == -1) { /* out of request ids: just fail this one */ fail_call(server, rc); return GRPC_CALL_OK; } switch (rc->type) { case BATCH_CALL: request_matcher = &server->unregistered_request_matcher; break; case REGISTERED_CALL: request_matcher = &rc->data.registered.registered_method->request_matcher; break; } server->requested_calls[request_id] = *rc; gpr_free(rc); if (gpr_stack_lockfree_push(request_matcher->requests, request_id)) { /* this was the first queued request: we need to lock and start matching calls */ gpr_mu_lock(&server->mu_call); while ((calld = request_matcher->pending_head) != NULL) { request_id = gpr_stack_lockfree_pop(request_matcher->requests); if (request_id == -1) break; request_matcher->pending_head = calld->pending_next; gpr_mu_unlock(&server->mu_call); gpr_mu_lock(&calld->mu_state); if (calld->state == ZOMBIED) { gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init( &calld->kill_zombie_closure, kill_zombie, grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); grpc_iomgr_add_callback(&calld->kill_zombie_closure); } else { GPR_ASSERT(calld->state == PENDING); calld->state = ACTIVATED; gpr_mu_unlock(&calld->mu_state); begin_call(server, calld, &server->requested_calls[request_id]); } gpr_mu_lock(&server->mu_call); } gpr_mu_unlock(&server->mu_call); } return GRPC_CALL_OK; } grpc_call_error grpc_server_request_call( grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *initial_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag) { requested_call *rc = gpr_malloc(sizeof(*rc)); GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notification, tag); if (!grpc_cq_is_server_cq(cq_for_notification)) { gpr_free(rc); return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; } grpc_cq_begin_op(cq_for_notification); details->reserved = NULL; rc->type = BATCH_CALL; rc->server = server; rc->tag = tag; rc->cq_bound_to_call = cq_bound_to_call; rc->cq_for_notification = cq_for_notification; rc->call = call; rc->data.batch.details = details; rc->data.batch.initial_metadata = initial_metadata; return queue_call_request(server, rc); } grpc_call_error grpc_server_request_registered_call( grpc_server *server, void *rm, grpc_call **call, gpr_timespec *deadline, grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag) { requested_call *rc = gpr_malloc(sizeof(*rc)); registered_method *registered_method = rm; if (!grpc_cq_is_server_cq(cq_for_notification)) { gpr_free(rc); return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; } grpc_cq_begin_op(cq_for_notification); rc->type = REGISTERED_CALL; rc->server = server; rc->tag = tag; rc->cq_bound_to_call = cq_bound_to_call; rc->cq_for_notification = cq_for_notification; rc->call = call; rc->data.registered.registered_method = registered_method; rc->data.registered.deadline = deadline; rc->data.registered.initial_metadata = initial_metadata; rc->data.registered.optional_payload = optional_payload; return queue_call_request(server, rc); } static void publish_registered_or_batch(grpc_call *call, int success, void *tag); static void publish_was_not_set(grpc_call *call, int success, void *tag) { abort(); } static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { gpr_slice slice = value->slice; size_t len = GPR_SLICE_LENGTH(slice); if (len + 1 > *capacity) { *capacity = GPR_MAX(len + 1, *capacity * 2); *dest = gpr_realloc(*dest, *capacity); } memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1); } static void begin_call(grpc_server *server, call_data *calld, requested_call *rc) { grpc_ioreq_completion_func publish = publish_was_not_set; grpc_ioreq req[2]; grpc_ioreq *r = req; /* called once initial metadata has been read by the call, but BEFORE the ioreq to fetch it out of the call has been executed. This means metadata related fields can be relied on in calld, but to fill in the metadata array passed by the client, we need to perform an ioreq op, that should complete immediately. */ grpc_call_set_completion_queue(calld->call, rc->cq_bound_to_call); *rc->call = calld->call; calld->cq_new = rc->cq_for_notification; switch (rc->type) { case BATCH_CALL: GPR_ASSERT(calld->host != NULL); GPR_ASSERT(calld->path != NULL); cpstr(&rc->data.batch.details->host, &rc->data.batch.details->host_capacity, calld->host); cpstr(&rc->data.batch.details->method, &rc->data.batch.details->method_capacity, calld->path); rc->data.batch.details->deadline = calld->deadline; r->op = GRPC_IOREQ_RECV_INITIAL_METADATA; r->data.recv_metadata = rc->data.batch.initial_metadata; r->flags = 0; r++; publish = publish_registered_or_batch; break; case REGISTERED_CALL: *rc->data.registered.deadline = calld->deadline; r->op = GRPC_IOREQ_RECV_INITIAL_METADATA; r->data.recv_metadata = rc->data.registered.initial_metadata; r->flags = 0; r++; if (rc->data.registered.optional_payload) { r->op = GRPC_IOREQ_RECV_MESSAGE; r->data.recv_message = rc->data.registered.optional_payload; r->flags = 0; r++; } publish = publish_registered_or_batch; break; } GRPC_CALL_INTERNAL_REF(calld->call, "server"); grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc); } static void done_request_event(void *req, grpc_cq_completion *c) { requested_call *rc = req; grpc_server *server = rc->server; if (rc >= server->requested_calls && rc < server->requested_calls + server->max_requested_calls) { gpr_stack_lockfree_push(server->request_freelist, rc - server->requested_calls); } else { gpr_free(req); } server_unref(server); } static void fail_call(grpc_server *server, requested_call *rc) { *rc->call = NULL; switch (rc->type) { case BATCH_CALL: rc->data.batch.initial_metadata->count = 0; break; case REGISTERED_CALL: rc->data.registered.initial_metadata->count = 0; break; } server_ref(server); grpc_cq_end_op(rc->cq_for_notification, rc->tag, 0, done_request_event, rc, &rc->completion); } static void publish_registered_or_batch(grpc_call *call, int success, void *prc) { grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); requested_call *rc = prc; call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; server_ref(chand->server); grpc_cq_end_op(calld->cq_new, rc->tag, success, done_request_event, rc, &rc->completion); GRPC_CALL_INTERNAL_UNREF(call, "server", 0); } const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) { return server->channel_args; } int grpc_server_has_open_connections(grpc_server *server) { int r; gpr_mu_lock(&server->mu_global); r = server->root_channel_data.next != &server->root_channel_data; gpr_mu_unlock(&server->mu_global); return r; } grpc-0.11.1/src/core/surface/channel_connectivity.c0000644000175000017500000001414312600663151022443 0ustar apollockapollock/* * * 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/surface/channel.h" #include #include #include "src/core/channel/client_channel.h" #include "src/core/iomgr/alarm.h" #include "src/core/surface/completion_queue.h" grpc_connectivity_state grpc_channel_check_connectivity_state( grpc_channel *channel, int try_to_connect) { /* forward through to the underlying client channel */ grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); if (client_channel_elem->filter != &grpc_client_channel_filter) { gpr_log(GPR_ERROR, "grpc_channel_check_connectivity_state called on something that is " "not a client channel, but '%s'", client_channel_elem->filter->name); return GRPC_CHANNEL_FATAL_FAILURE; } return grpc_client_channel_check_connectivity_state(client_channel_elem, try_to_connect); } typedef enum { WAITING, CALLING_BACK, CALLING_BACK_AND_FINISHED, CALLED_BACK } callback_phase; typedef struct { gpr_mu mu; callback_phase phase; int success; grpc_iomgr_closure on_complete; grpc_alarm alarm; grpc_connectivity_state state; grpc_completion_queue *cq; grpc_cq_completion completion_storage; grpc_channel *channel; void *tag; } state_watcher; static void delete_state_watcher(state_watcher *w) { grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( grpc_channel_get_channel_stack(w->channel)); grpc_client_channel_del_interested_party(client_channel_elem, grpc_cq_pollset(w->cq)); GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity"); gpr_mu_destroy(&w->mu); gpr_free(w); } static void finished_completion(void *pw, grpc_cq_completion *ignored) { int delete = 0; state_watcher *w = pw; gpr_mu_lock(&w->mu); switch (w->phase) { case WAITING: case CALLED_BACK: gpr_log(GPR_ERROR, "should never reach here"); abort(); break; case CALLING_BACK: w->phase = CALLED_BACK; break; case CALLING_BACK_AND_FINISHED: delete = 1; break; } gpr_mu_unlock(&w->mu); if (delete) { delete_state_watcher(w); } } static void partly_done(state_watcher *w, int due_to_completion) { int delete = 0; if (due_to_completion) { gpr_mu_lock(&w->mu); w->success = 1; gpr_mu_unlock(&w->mu); grpc_alarm_cancel(&w->alarm); } gpr_mu_lock(&w->mu); switch (w->phase) { case WAITING: w->phase = CALLING_BACK; grpc_cq_end_op(w->cq, w->tag, w->success, finished_completion, w, &w->completion_storage); break; case CALLING_BACK: w->phase = CALLING_BACK_AND_FINISHED; break; case CALLING_BACK_AND_FINISHED: gpr_log(GPR_ERROR, "should never reach here"); abort(); break; case CALLED_BACK: delete = 1; break; } gpr_mu_unlock(&w->mu); if (delete) { delete_state_watcher(w); } } static void watch_complete(void *pw, int success) { partly_done(pw, 1); } static void timeout_complete(void *pw, int success) { partly_done(pw, 0); } void grpc_channel_watch_connectivity_state( grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); state_watcher *w = gpr_malloc(sizeof(*w)); grpc_cq_begin_op(cq); gpr_mu_init(&w->mu); grpc_iomgr_closure_init(&w->on_complete, watch_complete, w); w->phase = WAITING; w->state = last_observed_state; w->success = 0; w->cq = cq; w->tag = tag; w->channel = channel; grpc_alarm_init(&w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); if (client_channel_elem->filter != &grpc_client_channel_filter) { gpr_log(GPR_ERROR, "grpc_channel_watch_connectivity_state called on something that is " "not a client channel, but '%s'", client_channel_elem->filter->name); grpc_iomgr_add_delayed_callback(&w->on_complete, 1); } else { GRPC_CHANNEL_INTERNAL_REF(channel, "watch_connectivity"); grpc_client_channel_add_interested_party(client_channel_elem, grpc_cq_pollset(cq)); grpc_client_channel_watch_connectivity_state(client_channel_elem, &w->state, &w->on_complete); } } grpc-0.11.1/src/core/surface/call.h0000644000175000017500000001621512600663151017157 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SURFACE_CALL_H #define GRPC_INTERNAL_CORE_SURFACE_CALL_H #include "src/core/channel/channel_stack.h" #include "src/core/channel/context.h" #include #ifdef __cplusplus extern "C" { #endif /* Primitive operation types - grpc_op's get rewritten into these */ typedef enum { GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_IOREQ_RECV_MESSAGE, GRPC_IOREQ_RECV_TRAILING_METADATA, GRPC_IOREQ_RECV_STATUS, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_IOREQ_RECV_CLOSE, GRPC_IOREQ_SEND_INITIAL_METADATA, GRPC_IOREQ_SEND_MESSAGE, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_IOREQ_SEND_STATUS, GRPC_IOREQ_SEND_CLOSE, GRPC_IOREQ_OP_COUNT } grpc_ioreq_op; typedef union { grpc_metadata_array *recv_metadata; grpc_byte_buffer **recv_message; struct { void (*set_value)(grpc_status_code status, void *user_data); void *user_data; } recv_status; struct { char **details; size_t *details_capacity; } recv_status_details; struct { size_t count; grpc_metadata *metadata; } send_metadata; grpc_byte_buffer *send_message; struct { grpc_status_code code; grpc_mdstr *details; } send_status; } grpc_ioreq_data; typedef struct { grpc_ioreq_op op; gpr_uint32 flags; /**< A copy of the write flags from grpc_op */ grpc_ioreq_data data; } grpc_ioreq; typedef void (*grpc_ioreq_completion_func)(grpc_call *call, int success, void *user_data); grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask, grpc_completion_queue *cq, const void *server_transport_data, grpc_mdelem **add_initial_metadata, size_t add_initial_metadata_count, gpr_timespec send_deadline); void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq); grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call); #ifdef GRPC_CALL_REF_COUNT_DEBUG void grpc_call_internal_ref(grpc_call *call, const char *reason); void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion); #define GRPC_CALL_INTERNAL_REF(call, reason) \ grpc_call_internal_ref(call, reason) #define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) \ grpc_call_internal_unref(call, reason, allow_immediate_deletion) #else void grpc_call_internal_ref(grpc_call *call); void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion); #define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call) #define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) \ grpc_call_internal_unref(call, allow_immediate_deletion) #endif grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, grpc_ioreq_completion_func on_complete, void *user_data); grpc_call_stack *grpc_call_get_call_stack(grpc_call *call); /* Given the top call_element, get the call object. */ grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element); extern int grpc_trace_batch; void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, grpc_call *call, const grpc_op *ops, size_t nops, void *tag); void grpc_server_log_request_call(char *file, int line, gpr_log_severity severity, grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *initial_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag); void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity, grpc_server *server, grpc_completion_queue *cq, void *tag); /* Set a context pointer. No thread safety guarantees are made wrt this value. */ void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value, void (*destroy)(void *value)); /* Get a context pointer. */ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); #define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \ if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag) #define GRPC_SERVER_LOG_REQUEST_CALL(sev, server, call, details, \ initial_metadata, cq_bound_to_call, \ cq_for_notifications, tag) \ if (grpc_trace_batch) \ grpc_server_log_request_call(sev, server, call, details, initial_metadata, \ cq_bound_to_call, cq_for_notifications, tag) #define GRPC_SERVER_LOG_SHUTDOWN(sev, server, cq, tag) \ if (grpc_trace_batch) grpc_server_log_shutdown(sev, server, cq, tag) gpr_uint8 grpc_call_is_client(grpc_call *call); grpc_compression_algorithm grpc_call_get_compression_algorithm( const grpc_call *call); gpr_uint32 grpc_call_get_message_flags(const grpc_call *call); /** Returns a bitset for the encodings (compression algorithms) supported by \a * call's peer. * * To be indexed by grpc_compression_algorithm enum values. */ gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */ grpc-0.11.1/src/core/surface/byte_buffer_queue.c0000644000175000017500000000637212600663151021742 0ustar apollockapollock/* * * 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/surface/byte_buffer_queue.h" #include #include static void bba_destroy(grpc_bbq_array *array, size_t start_pos) { size_t i; for (i = start_pos; i < array->count; i++) { grpc_byte_buffer_destroy(array->data[i]); } gpr_free(array->data); } /* Append an operation to an array, expanding as needed */ static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) { if (a->count == a->capacity) { a->capacity = GPR_MAX(a->capacity * 2, 8); a->data = gpr_realloc(a->data, sizeof(grpc_byte_buffer *) * a->capacity); } a->data[a->count++] = buffer; } void grpc_bbq_destroy(grpc_byte_buffer_queue *q) { bba_destroy(&q->filling, 0); bba_destroy(&q->draining, q->drain_pos); } int grpc_bbq_empty(grpc_byte_buffer_queue *q) { return (q->drain_pos == q->draining.count && q->filling.count == 0); } void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *buffer) { q->bytes += grpc_byte_buffer_length(buffer); bba_push(&q->filling, buffer); } void grpc_bbq_flush(grpc_byte_buffer_queue *q) { grpc_byte_buffer *bb; while ((bb = grpc_bbq_pop(q))) { grpc_byte_buffer_destroy(bb); } } size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q) { return q->bytes; } grpc_byte_buffer *grpc_bbq_pop(grpc_byte_buffer_queue *q) { grpc_bbq_array temp_array; grpc_byte_buffer *out; if (q->drain_pos == q->draining.count) { if (q->filling.count == 0) { return NULL; } q->draining.count = 0; q->drain_pos = 0; /* swap arrays */ temp_array = q->filling; q->filling = q->draining; q->draining = temp_array; } out = q->draining.data[q->drain_pos++]; q->bytes -= grpc_byte_buffer_length(out); return out; } grpc-0.11.1/src/core/surface/secure_channel_create.c0000644000175000017500000002221312600663151022533 0ustar apollockapollock/* * * 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 #include #include #include #include "src/core/census/grpc_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/channel/client_channel.h" #include "src/core/channel/compress_filter.h" #include "src/core/channel/http_client_filter.h" #include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/security/auth_filters.h" #include "src/core/security/credentials.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/surface/channel.h" #include "src/core/transport/chttp2_transport.h" #include "src/core/tsi/transport_security_interface.h" typedef struct { grpc_connector base; gpr_refcount refs; grpc_channel_security_connector *security_connector; grpc_iomgr_closure *notify; grpc_connect_in_args args; grpc_connect_out_args *result; } connector; static void connector_ref(grpc_connector *con) { connector *c = (connector *)con; gpr_ref(&c->refs); } static void connector_unref(grpc_connector *con) { connector *c = (connector *)con; if (gpr_unref(&c->refs)) { gpr_free(c); } } static void on_secure_transport_setup_done(void *arg, grpc_security_status status, grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint) { connector *c = arg; grpc_iomgr_closure *notify; if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); memset(c->result, 0, sizeof(*c->result)); } else { c->result->transport = grpc_create_chttp2_transport( c->args.channel_args, secure_endpoint, c->args.metadata_context, 1); grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0); c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2); c->result->filters[0] = &grpc_http_client_filter; c->result->filters[1] = &grpc_client_auth_filter; c->result->num_filters = 2; } notify = c->notify; c->notify = NULL; grpc_iomgr_add_callback(notify); } static void connected(void *arg, grpc_endpoint *tcp) { connector *c = arg; grpc_iomgr_closure *notify; if (tcp != NULL) { grpc_setup_secure_transport(&c->security_connector->base, tcp, on_secure_transport_setup_done, c); } else { memset(c->result, 0, sizeof(*c->result)); notify = c->notify; c->notify = NULL; grpc_iomgr_add_callback(notify); } } static void connector_connect(grpc_connector *con, const grpc_connect_in_args *args, grpc_connect_out_args *result, grpc_iomgr_closure *notify) { connector *c = (connector *)con; GPR_ASSERT(c->notify == NULL); GPR_ASSERT(notify->cb); c->notify = notify; c->args = *args; c->result = result; grpc_tcp_client_connect(connected, c, args->interested_parties, args->addr, args->addr_len, args->deadline); } static const grpc_connector_vtable connector_vtable = { connector_ref, connector_unref, connector_connect}; typedef struct { grpc_subchannel_factory base; gpr_refcount refs; grpc_mdctx *mdctx; grpc_channel_args *merge_args; grpc_channel_security_connector *security_connector; grpc_channel *master; } subchannel_factory; static void subchannel_factory_ref(grpc_subchannel_factory *scf) { subchannel_factory *f = (subchannel_factory *)scf; gpr_ref(&f->refs); } static void subchannel_factory_unref(grpc_subchannel_factory *scf) { subchannel_factory *f = (subchannel_factory *)scf; if (gpr_unref(&f->refs)) { GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base, "subchannel_factory"); GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory"); grpc_channel_args_destroy(f->merge_args); grpc_mdctx_unref(f->mdctx); gpr_free(f); } } static grpc_subchannel *subchannel_factory_create_subchannel( grpc_subchannel_factory *scf, grpc_subchannel_args *args) { subchannel_factory *f = (subchannel_factory *)scf; connector *c = gpr_malloc(sizeof(*c)); grpc_channel_args *final_args = grpc_channel_args_merge(args->args, f->merge_args); grpc_subchannel *s; memset(c, 0, sizeof(*c)); c->base.vtable = &connector_vtable; c->security_connector = f->security_connector; gpr_ref_init(&c->refs, 1); args->mdctx = f->mdctx; args->args = final_args; args->master = f->master; s = grpc_subchannel_create(&c->base, args); grpc_connector_unref(&c->base); grpc_channel_args_destroy(final_args); return s; } static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { subchannel_factory_ref, subchannel_factory_unref, subchannel_factory_create_subchannel}; /* Create a secure client channel: Asynchronously: - resolve target - connect to it (trying alternatives as presented) - perform handshakes */ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const char *target, const grpc_channel_args *args, void *reserved) { grpc_channel *channel; grpc_arg connector_arg; grpc_channel_args *args_copy; grpc_channel_args *new_args_from_connector; grpc_channel_security_connector *connector; grpc_mdctx *mdctx; grpc_resolver *resolver; subchannel_factory *f; #define MAX_FILTERS 3 const grpc_channel_filter *filters[MAX_FILTERS]; int n = 0; GPR_ASSERT(reserved == NULL); if (grpc_find_security_connector_in_args(args) != NULL) { gpr_log(GPR_ERROR, "Cannot set security context in channel args."); return grpc_lame_client_channel_create( target, GRPC_STATUS_INVALID_ARGUMENT, "Security connector exists in channel args."); } if (grpc_credentials_create_security_connector( creds, target, args, NULL, &connector, &new_args_from_connector) != GRPC_SECURITY_OK) { return grpc_lame_client_channel_create( target, GRPC_STATUS_INVALID_ARGUMENT, "Failed to create security connector."); } mdctx = grpc_mdctx_create(); connector_arg = grpc_security_connector_to_arg(&connector->base); args_copy = grpc_channel_args_copy_and_add( new_args_from_connector != NULL ? new_args_from_connector : args, &connector_arg, 1); if (grpc_channel_args_is_census_enabled(args)) { filters[n++] = &grpc_client_census_filter; } filters[n++] = &grpc_compress_filter; filters[n++] = &grpc_client_channel_filter; GPR_ASSERT(n <= MAX_FILTERS); channel = grpc_channel_create_from_filters(target, filters, n, args_copy, mdctx, 1); f = gpr_malloc(sizeof(*f)); f->base.vtable = &subchannel_factory_vtable; gpr_ref_init(&f->refs, 1); grpc_mdctx_ref(mdctx); f->mdctx = mdctx; GRPC_SECURITY_CONNECTOR_REF(&connector->base, "subchannel_factory"); f->security_connector = connector; f->merge_args = grpc_channel_args_copy(args_copy); f->master = channel; GRPC_CHANNEL_INTERNAL_REF(channel, "subchannel_factory"); resolver = grpc_resolver_create(target, &f->base); if (!resolver) { return NULL; } grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel), resolver); GRPC_RESOLVER_UNREF(resolver, "create"); grpc_subchannel_factory_unref(&f->base); GRPC_SECURITY_CONNECTOR_UNREF(&connector->base, "channel_create"); grpc_channel_args_destroy(args_copy); if (new_args_from_connector != NULL) { grpc_channel_args_destroy(new_args_from_connector); } return channel; } grpc-0.11.1/src/core/surface/event_string.c0000644000175000017500000000522412600663151020744 0ustar apollockapollock/* * * 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/surface/event_string.h" #include #include "src/core/support/string.h" #include #include static void addhdr(gpr_strvec *buf, grpc_event *ev) { char *tmp; gpr_asprintf(&tmp, "tag:%p", ev->tag); gpr_strvec_add(buf, tmp); } static const char *errstr(int success) { return success ? "OK" : "ERROR"; } static void adderr(gpr_strvec *buf, int success) { char *tmp; gpr_asprintf(&tmp, " %s", errstr(success)); gpr_strvec_add(buf, tmp); } char *grpc_event_string(grpc_event *ev) { char *out; gpr_strvec buf; if (ev == NULL) return gpr_strdup("null"); gpr_strvec_init(&buf); switch (ev->type) { case GRPC_QUEUE_TIMEOUT: gpr_strvec_add(&buf, gpr_strdup("QUEUE_TIMEOUT")); break; case GRPC_QUEUE_SHUTDOWN: gpr_strvec_add(&buf, gpr_strdup("QUEUE_SHUTDOWN")); break; case GRPC_OP_COMPLETE: gpr_strvec_add(&buf, gpr_strdup("OP_COMPLETE: ")); addhdr(&buf, ev); adderr(&buf, ev->success); break; } out = gpr_strvec_flatten(&buf, NULL); gpr_strvec_destroy(&buf); return out; } grpc-0.11.1/src/core/debug/0000755000175000017500000000000012600663151015524 5ustar apollockapollockgrpc-0.11.1/src/core/debug/trace.h0000644000175000017500000000352712600663151017002 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_DEBUG_TRACE_H #define GRPC_INTERNAL_CORE_DEBUG_TRACE_H #include void grpc_register_tracer(const char *name, int *flag); void grpc_tracer_init(const char *env_var_name); void grpc_tracer_shutdown(void); #endif /* GRPC_INTERNAL_CORE_DEBUG_TRACE_H */ grpc-0.11.1/src/core/debug/trace.c0000644000175000017500000000700012600663151016763 0ustar apollockapollock/* * * 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/debug/trace.h" #include #include #include #include #include "src/core/support/env.h" typedef struct tracer { const char *name; int *flag; struct tracer *next; } tracer; static tracer *tracers; void grpc_register_tracer(const char *name, int *flag) { tracer *t = gpr_malloc(sizeof(*t)); t->name = name; t->flag = flag; t->next = tracers; *flag = 0; tracers = t; } static void add(const char *beg, const char *end, char ***ss, size_t *ns) { size_t n = *ns; size_t np = n + 1; char *s = gpr_malloc(end - beg + 1); memcpy(s, beg, end - beg); s[end - beg] = 0; *ss = gpr_realloc(*ss, sizeof(char **) * np); (*ss)[n] = s; *ns = np; } static void split(const char *s, char ***ss, size_t *ns) { const char *c = strchr(s, ','); if (c == NULL) { add(s, s + strlen(s), ss, ns); } else { add(s, c, ss, ns); split(c + 1, ss, ns); } } static void parse(const char *s) { char **strings = NULL; size_t nstrings = 0; size_t i; split(s, &strings, &nstrings); for (i = 0; i < nstrings; i++) { grpc_tracer_set_enabled(strings[i], 1); } for (i = 0; i < nstrings; i++) { gpr_free(strings[i]); } gpr_free(strings); } void grpc_tracer_init(const char *env_var) { char *e = gpr_getenv(env_var); if (e != NULL) { parse(e); gpr_free(e); } } void grpc_tracer_shutdown(void) { while (tracers) { tracer *t = tracers; tracers = t->next; gpr_free(t); } } int grpc_tracer_set_enabled(const char *name, int enabled) { tracer *t; if (0 == strcmp(name, "all")) { for (t = tracers; t; t = t->next) { *t->flag = 1; } } else { int found = 0; for (t = tracers; t; t = t->next) { if (0 == strcmp(name, t->name)) { *t->flag = enabled; found = 1; } } if (!found) { gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name); return 0; /* early return */ } } return 1; } grpc-0.11.1/src/core/statistics/0000755000175000017500000000000012600663151016630 5ustar apollockapollockgrpc-0.11.1/src/core/statistics/census_log.h0000644000175000017500000000770112600663151021147 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H #define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H #include /* Maximum record size, in bytes. */ #define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */ #define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE) /* Initialize the statistics logging subsystem with the given log size. A log size of 0 will result in the smallest possible log for the platform (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If discard_old_records is non-zero, then new records will displace older ones when the log is full. This function must be called before any other census_log functions. */ void census_log_initialize(size_t size_in_mb, int discard_old_records); /* Shutdown the logging subsystem. Caller must ensure that: - no in progress or future call to any census_log functions - no incomplete records */ void census_log_shutdown(void); /* Allocates and returns a 'size' bytes record and marks it in use. A subsequent census_log_end_write() marks the record complete. The 'bytes_written' census_log_end_write() argument must be <= 'size'. Returns NULL if out-of-space AND: - log is configured to keep old records OR - all blocks are pinned by incomplete records. */ void* census_log_start_write(size_t size); void census_log_end_write(void* record, size_t bytes_written); /* census_log_read_next() iterates over blocks with data and for each block returns a pointer to the first unread byte. The number of bytes that can be read are returned in 'bytes_available'. Reader is expected to read all available data. Reading the data consumes it i.e. it cannot be read again. census_log_read_next() returns NULL if the end is reached i.e last block is read. census_log_init_reader() starts the iteration or aborts the current iteration. */ void census_log_init_reader(void); const void* census_log_read_next(size_t* bytes_available); /* Returns estimated remaining space across all blocks, in bytes. If log is configured to discard old records, returns total log space. Otherwise, returns space available in empty blocks (partially filled blocks are treated as full). */ size_t census_log_remaining_space(void); /* Returns the number of times gprc_stats_log_start_write() failed due to out-of-space. */ int census_log_out_of_space_count(void); #endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H */ grpc-0.11.1/src/core/statistics/hash_table.c0000644000175000017500000002220512600663151021067 0ustar apollockapollock/* * * 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/statistics/hash_table.h" #include #include #include #include #include #define CENSUS_HT_NUM_BUCKETS 1999 /* A single hash table data entry */ typedef struct ht_entry { census_ht_key key; void* data; struct ht_entry* next; } ht_entry; /* hash table bucket */ typedef struct bucket { /* NULL if bucket is empty */ ht_entry* next; /* -1 if all buckets are empty. */ gpr_int32 prev_non_empty_bucket; /* -1 if all buckets are empty. */ gpr_int32 next_non_empty_bucket; } bucket; struct unresizable_hash_table { /* Number of entries in the table */ size_t size; /* Number of buckets */ gpr_uint32 num_buckets; /* Array of buckets initialized at creation time. Memory consumption is 16 bytes per bucket on a 64-bit platform. */ bucket* buckets; /* Index of the first non-empty bucket. -1 iff size == 0. */ gpr_int32 first_non_empty_bucket; /* Index of the last non_empty bucket. -1 iff size == 0. */ gpr_int32 last_non_empty_bucket; /* Immutable options of this hash table, initialized at creation time. */ census_ht_option options; }; typedef struct entry_locator { gpr_int32 bucket_idx; int is_first_in_chain; int found; ht_entry* prev_entry; } entry_locator; /* Asserts if option is not valid. */ void check_options(const census_ht_option* option) { GPR_ASSERT(option != NULL); GPR_ASSERT(option->num_buckets > 0); GPR_ASSERT(option->key_type == CENSUS_HT_UINT64 || option->key_type == CENSUS_HT_POINTER); if (option->key_type == CENSUS_HT_UINT64) { GPR_ASSERT(option->hash == NULL); } else if (option->key_type == CENSUS_HT_POINTER) { GPR_ASSERT(option->hash != NULL); GPR_ASSERT(option->compare_keys != NULL); } } #define REMOVE_NEXT(options, ptr) \ do { \ ht_entry* tmp = (ptr)->next; \ (ptr)->next = tmp->next; \ delete_entry(options, tmp); \ } while (0) static void delete_entry(const census_ht_option* opt, ht_entry* p) { if (opt->delete_data != NULL) { opt->delete_data(p->data); } if (opt->delete_key != NULL) { opt->delete_key(p->key.ptr); } gpr_free(p); } static gpr_uint64 hash(const census_ht_option* opt, census_ht_key key) { return opt->key_type == CENSUS_HT_UINT64 ? key.val : opt->hash(key.ptr); } census_ht* census_ht_create(const census_ht_option* option) { int i; census_ht* ret = NULL; check_options(option); ret = (census_ht*)gpr_malloc(sizeof(census_ht)); ret->size = 0; ret->num_buckets = option->num_buckets; ret->buckets = (bucket*)gpr_malloc(sizeof(bucket) * ret->num_buckets); ret->options = *option; /* initialize each bucket */ for (i = 0; i < ret->options.num_buckets; i++) { ret->buckets[i].prev_non_empty_bucket = -1; ret->buckets[i].next_non_empty_bucket = -1; ret->buckets[i].next = NULL; } return ret; } static gpr_int32 find_bucket_idx(const census_ht* ht, census_ht_key key) { return hash(&ht->options, key) % ht->num_buckets; } static int keys_match(const census_ht_option* opt, const ht_entry* p, const census_ht_key key) { GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 || opt->key_type == CENSUS_HT_POINTER); if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val; return !opt->compare_keys((p->key).ptr, key.ptr); } static entry_locator ht_find(const census_ht* ht, census_ht_key key) { entry_locator loc = {0, 0, 0, NULL}; gpr_int32 idx = 0; ht_entry* ptr = NULL; GPR_ASSERT(ht != NULL); idx = find_bucket_idx(ht, key); ptr = ht->buckets[idx].next; if (ptr == NULL) { /* bucket is empty */ return loc; } if (keys_match(&ht->options, ptr, key)) { loc.bucket_idx = idx; loc.is_first_in_chain = 1; loc.found = 1; return loc; } else { for (; ptr->next != NULL; ptr = ptr->next) { if (keys_match(&ht->options, ptr->next, key)) { loc.bucket_idx = idx; loc.is_first_in_chain = 0; loc.found = 1; loc.prev_entry = ptr; return loc; } } } /* Could not find the key */ return loc; } void* census_ht_find(const census_ht* ht, census_ht_key key) { entry_locator loc = ht_find(ht, key); if (loc.found == 0) { return NULL; } return loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next->data : loc.prev_entry->next->data; } void census_ht_insert(census_ht* ht, census_ht_key key, void* data) { gpr_int32 idx = find_bucket_idx(ht, key); ht_entry* ptr = NULL; entry_locator loc = ht_find(ht, key); if (loc.found) { /* Replace old value with new value. */ ptr = loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next : loc.prev_entry->next; if (ht->options.delete_data != NULL) { ht->options.delete_data(ptr->data); } ptr->data = data; return; } /* first entry in the table. */ if (ht->size == 0) { ht->buckets[idx].next_non_empty_bucket = -1; ht->buckets[idx].prev_non_empty_bucket = -1; ht->first_non_empty_bucket = idx; ht->last_non_empty_bucket = idx; } else if (ht->buckets[idx].next == NULL) { /* first entry in the bucket. */ ht->buckets[ht->last_non_empty_bucket].next_non_empty_bucket = idx; ht->buckets[idx].prev_non_empty_bucket = ht->last_non_empty_bucket; ht->buckets[idx].next_non_empty_bucket = -1; ht->last_non_empty_bucket = idx; } ptr = (ht_entry*)gpr_malloc(sizeof(ht_entry)); ptr->key = key; ptr->data = data; ptr->next = ht->buckets[idx].next; ht->buckets[idx].next = ptr; ht->size++; } void census_ht_erase(census_ht* ht, census_ht_key key) { entry_locator loc = ht_find(ht, key); if (loc.found == 0) { /* noop if not found */ return; } ht->size--; if (loc.is_first_in_chain) { bucket* b = &ht->buckets[loc.bucket_idx]; GPR_ASSERT(b->next != NULL); /* The only entry in the bucket */ if (b->next->next == NULL) { int prev = b->prev_non_empty_bucket; int next = b->next_non_empty_bucket; if (prev != -1) { ht->buckets[prev].next_non_empty_bucket = next; } else { ht->first_non_empty_bucket = next; } if (next != -1) { ht->buckets[next].prev_non_empty_bucket = prev; } else { ht->last_non_empty_bucket = prev; } } REMOVE_NEXT(&ht->options, b); } else { GPR_ASSERT(loc.prev_entry->next != NULL); REMOVE_NEXT(&ht->options, loc.prev_entry); } } /* Returns NULL if input table is empty. */ census_ht_kv* census_ht_get_all_elements(const census_ht* ht, size_t* num) { census_ht_kv* ret = NULL; int i = 0; gpr_int32 idx = -1; GPR_ASSERT(ht != NULL && num != NULL); *num = ht->size; if (*num == 0) { return NULL; } ret = (census_ht_kv*)gpr_malloc(sizeof(census_ht_kv) * ht->size); idx = ht->first_non_empty_bucket; while (idx >= 0) { ht_entry* ptr = ht->buckets[idx].next; for (; ptr != NULL; ptr = ptr->next) { ret[i].k = ptr->key; ret[i].v = ptr->data; i++; } idx = ht->buckets[idx].next_non_empty_bucket; } return ret; } static void ht_delete_entry_chain(const census_ht_option* options, ht_entry* first) { if (first == NULL) { return; } if (first->next != NULL) { ht_delete_entry_chain(options, first->next); } delete_entry(options, first); } void census_ht_destroy(census_ht* ht) { unsigned i; for (i = 0; i < ht->num_buckets; ++i) { ht_delete_entry_chain(&ht->options, ht->buckets[i].next); } gpr_free(ht->buckets); gpr_free(ht); } size_t census_ht_get_size(const census_ht* ht) { return ht->size; } grpc-0.11.1/src/core/statistics/hash_table.h0000644000175000017500000001261512600663151021100 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H #define GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H #include #include /* A chain based hash table with fixed number of buckets. Your probably shouldn't use this code directly. It is implemented for the use case in census trace store and stats store, where number of entries in the table is in the scale of upto several thousands, entries are added and removed from the table very frequently (~100k/s), the frequency of find() operations is roughly several times of the frequency of insert() and erase() Comparing to find(), the insert(), erase() and get_all_entries() operations are much less freqent (<1/s). Per bucket memory overhead is about (8 + sizeof(intptr_t) bytes. Per entry memory overhead is about (8 + 2 * sizeof(intptr_t) bytes. All functions are not thread-safe. Synchronization will be provided in the upper layer (in trace store and stats store). */ /* Opaque hash table struct */ typedef struct unresizable_hash_table census_ht; /* Currently, the hash_table can take two types of keys. (uint64 for trace store and const char* for stats store). */ typedef union { gpr_uint64 val; void* ptr; } census_ht_key; typedef enum census_ht_key_type { CENSUS_HT_UINT64 = 0, CENSUS_HT_POINTER = 1 } census_ht_key_type; typedef struct census_ht_option { /* Type of hash key */ census_ht_key_type key_type; /* Desired number of buckets, preferably a prime number */ gpr_int32 num_buckets; /* Fucntion to calculate uint64 hash value of the key. Only takes effect if key_type is POINTER. */ gpr_uint64 (*hash)(const void*); /* Function to compare two keys, returns 0 iff equal. Only takes effect if key_type is POINTER */ int (*compare_keys)(const void* k1, const void* k2); /* Value deleter. NULL if no specialized delete function is needed. */ void (*delete_data)(void*); /* Key deleter. NULL if table does not own the key. (e.g. key is part of the value or key is not owned by the table.) */ void (*delete_key)(void*); } census_ht_option; /* Creates a hashtable with fixed number of buckets according to the settings specified in 'options' arg. Function pointers "hash" and "compare_keys" must be provided if key_type is POINTER. Asserts if fail to create. */ census_ht* census_ht_create(const census_ht_option* options); /* Deletes hash table instance. Frees all dynamic memory owned by ht.*/ void census_ht_destroy(census_ht* ht); /* Inserts the input key-val pair into hash_table. If an entry with the same key exists in the table, the corresponding value will be overwritten by the input val. */ void census_ht_insert(census_ht* ht, census_ht_key key, void* val); /* Returns pointer to data, returns NULL if not found. */ void* census_ht_find(const census_ht* ht, census_ht_key key); /* Erase hash table entry with input key. Noop if key is not found. */ void census_ht_erase(census_ht* ht, census_ht_key key); typedef struct census_ht_kv { census_ht_key k; void* v; } census_ht_kv; /* Returns an array of pointers to all values in the hash table. Order of the elements can be arbitrary. Sets 'num' to the size of returned array. Caller owns returned array. */ census_ht_kv* census_ht_get_all_elements(const census_ht* ht, size_t* num); /* Returns number of elements kept. */ size_t census_ht_get_size(const census_ht* ht); /* Functor applied on each key-value pair while iterating through entries in the table. The functor should not mutate data. */ typedef void (*census_ht_itr_cb)(census_ht_key key, const void* val_ptr, void* state); /* Iterates through all key-value pairs in the hash_table. The callback function should not invalidate data entries. */ gpr_uint64 census_ht_for_all(const census_ht* ht, census_ht_itr_cb); #endif /* GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H */ grpc-0.11.1/src/core/statistics/census_rpc_stats.c0000644000175000017500000002111512600663151022356 0ustar apollockapollock/* * * 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 #include "src/core/statistics/census_interface.h" #include "src/core/statistics/census_rpc_stats.h" #include "src/core/statistics/hash_table.h" #include "src/core/statistics/census_tracing.h" #include "src/core/statistics/window_stats.h" #include "src/core/support/murmur_hash.h" #include "src/core/support/string.h" #include #include #include #define NUM_INTERVALS 3 #define MINUTE_INTERVAL 0 #define HOUR_INTERVAL 1 #define TOTAL_INTERVAL 2 /* for easier typing */ typedef census_per_method_rpc_stats per_method_stats; /* Ensure mu is only initialized once. */ static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT; /* Guards two stats stores. */ static gpr_mu g_mu; static census_ht* g_client_stats_store = NULL; static census_ht* g_server_stats_store = NULL; static void init_mutex(void) { gpr_mu_init(&g_mu); } static void init_mutex_once(void) { gpr_once_init(&g_stats_store_mu_init, init_mutex); } static int cmp_str_keys(const void* k1, const void* k2) { return strcmp((const char*)k1, (const char*)k2); } /* TODO(hongyu): replace it with cityhash64 */ static gpr_uint64 simple_hash(const void* k) { size_t len = strlen(k); gpr_uint64 higher = gpr_murmur_hash3((const char*)k, len / 2, 0); return higher << 32 | gpr_murmur_hash3((const char*)k + len / 2, len - len / 2, 0); } static void delete_stats(void* stats) { census_window_stats_destroy((struct census_window_stats*)stats); } static void delete_key(void* key) { gpr_free(key); } static const census_ht_option ht_opt = { CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */, simple_hash /* hash function */, cmp_str_keys /* key comparator */, delete_stats /* data deleter */, delete_key /* key deleter */ }; static void init_rpc_stats(void* stats) { memset(stats, 0, sizeof(census_rpc_stats)); } static void stat_add_proportion(double p, void* base, const void* addme) { census_rpc_stats* b = (census_rpc_stats*)base; census_rpc_stats* a = (census_rpc_stats*)addme; b->cnt += p * a->cnt; b->rpc_error_cnt += p * a->rpc_error_cnt; b->app_error_cnt += p * a->app_error_cnt; b->elapsed_time_ms += p * a->elapsed_time_ms; b->api_request_bytes += p * a->api_request_bytes; b->wire_request_bytes += p * a->wire_request_bytes; b->api_response_bytes += p * a->api_response_bytes; b->wire_response_bytes += p * a->wire_response_bytes; } static void stat_add(void* base, const void* addme) { stat_add_proportion(1.0, base, addme); } static gpr_timespec min_hour_total_intervals[3] = { {60, 0}, {3600, 0}, {36000000, 0}}; static const census_window_stats_stat_info window_stats_settings = { sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion}; census_rpc_stats* census_rpc_stats_create_empty(void) { census_rpc_stats* ret = (census_rpc_stats*)gpr_malloc(sizeof(census_rpc_stats)); memset(ret, 0, sizeof(census_rpc_stats)); return ret; } void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats* data) { int i = 0; for (i = 0; i < data->num_entries; i++) { if (data->stats[i].method != NULL) { gpr_free((void*)data->stats[i].method); } } if (data->stats != NULL) { gpr_free(data->stats); } data->num_entries = 0; data->stats = NULL; } static void record_stats(census_ht* store, census_op_id op_id, const census_rpc_stats* stats) { gpr_mu_lock(&g_mu); if (store != NULL) { census_trace_obj* trace = NULL; census_internal_lock_trace_store(); trace = census_get_trace_obj_locked(op_id); if (trace != NULL) { const char* method_name = census_get_trace_method_name(trace); struct census_window_stats* window_stats = NULL; census_ht_key key; key.ptr = (void*)method_name; window_stats = census_ht_find(store, key); census_internal_unlock_trace_store(); if (window_stats == NULL) { window_stats = census_window_stats_create(3, min_hour_total_intervals, 30, &window_stats_settings); key.ptr = gpr_strdup(key.ptr); census_ht_insert(store, key, (void*)window_stats); } census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats); } else { census_internal_unlock_trace_store(); } } gpr_mu_unlock(&g_mu); } void census_record_rpc_client_stats(census_op_id op_id, const census_rpc_stats* stats) { record_stats(g_client_stats_store, op_id, stats); } void census_record_rpc_server_stats(census_op_id op_id, const census_rpc_stats* stats) { record_stats(g_server_stats_store, op_id, stats); } /* Get stats from input stats store */ static void get_stats(census_ht* store, census_aggregated_rpc_stats* data) { GPR_ASSERT(data != NULL); if (data->num_entries != 0) { census_aggregated_rpc_stats_set_empty(data); } gpr_mu_lock(&g_mu); if (store != NULL) { size_t n; unsigned i, j; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); census_ht_kv* kv = census_ht_get_all_elements(store, &n); if (kv != NULL) { data->num_entries = n; data->stats = (per_method_stats*)gpr_malloc(sizeof(per_method_stats) * n); for (i = 0; i < n; i++) { census_window_stats_sums sums[NUM_INTERVALS]; for (j = 0; j < NUM_INTERVALS; j++) { sums[j].statistic = (void*)census_rpc_stats_create_empty(); } data->stats[i].method = gpr_strdup(kv[i].k.ptr); census_window_stats_get_sums(kv[i].v, now, sums); data->stats[i].minute_stats = *(census_rpc_stats*)sums[MINUTE_INTERVAL].statistic; data->stats[i].hour_stats = *(census_rpc_stats*)sums[HOUR_INTERVAL].statistic; data->stats[i].total_stats = *(census_rpc_stats*)sums[TOTAL_INTERVAL].statistic; for (j = 0; j < NUM_INTERVALS; j++) { gpr_free(sums[j].statistic); } } gpr_free(kv); } } gpr_mu_unlock(&g_mu); } void census_get_client_stats(census_aggregated_rpc_stats* data) { get_stats(g_client_stats_store, data); } void census_get_server_stats(census_aggregated_rpc_stats* data) { get_stats(g_server_stats_store, data); } void census_stats_store_init(void) { init_mutex_once(); gpr_mu_lock(&g_mu); if (g_client_stats_store == NULL && g_server_stats_store == NULL) { g_client_stats_store = census_ht_create(&ht_opt); g_server_stats_store = census_ht_create(&ht_opt); } else { gpr_log(GPR_ERROR, "Census stats store already initialized."); } gpr_mu_unlock(&g_mu); } void census_stats_store_shutdown(void) { init_mutex_once(); gpr_mu_lock(&g_mu); if (g_client_stats_store != NULL) { census_ht_destroy(g_client_stats_store); g_client_stats_store = NULL; } else { gpr_log(GPR_ERROR, "Census server stats store not initialized."); } if (g_server_stats_store != NULL) { census_ht_destroy(g_server_stats_store); g_server_stats_store = NULL; } else { gpr_log(GPR_ERROR, "Census client stats store not initialized."); } gpr_mu_unlock(&g_mu); } grpc-0.11.1/src/core/statistics/census_tracing.c0000644000175000017500000001637512600663151022017 0ustar apollockapollock/* * * 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/statistics/census_interface.h" #include "src/core/statistics/census_tracing.h" #include #include #include "src/core/statistics/hash_table.h" #include "src/core/support/string.h" #include #include #include #include void census_trace_obj_destroy(census_trace_obj* obj) { census_trace_annotation* p = obj->annotations; while (p != NULL) { census_trace_annotation* next = p->next; gpr_free(p); p = next; } gpr_free(obj->method); gpr_free(obj); } static void delete_trace_obj(void* obj) { census_trace_obj_destroy((census_trace_obj*)obj); } static const census_ht_option ht_opt = { CENSUS_HT_UINT64 /* key type*/, 571 /* n_of_buckets */, NULL /* hash */, NULL /* compare_keys */, delete_trace_obj /* delete data */, NULL /* delete key */ }; static gpr_once g_init_mutex_once = GPR_ONCE_INIT; static gpr_mu g_mu; /* Guards following two static variables. */ static census_ht* g_trace_store = NULL; static gpr_uint64 g_id = 0; static census_ht_key op_id_as_key(census_op_id* id) { return *(census_ht_key*)id; } static gpr_uint64 op_id_2_uint64(census_op_id* id) { gpr_uint64 ret; memcpy(&ret, id, sizeof(census_op_id)); return ret; } static void init_mutex(void) { gpr_mu_init(&g_mu); } static void init_mutex_once(void) { gpr_once_init(&g_init_mutex_once, init_mutex); } census_op_id census_tracing_start_op(void) { gpr_mu_lock(&g_mu); { census_trace_obj* ret = gpr_malloc(sizeof(census_trace_obj)); memset(ret, 0, sizeof(census_trace_obj)); g_id++; memcpy(&ret->id, &g_id, sizeof(census_op_id)); ret->rpc_stats.cnt = 1; ret->ts = gpr_now(GPR_CLOCK_REALTIME); census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void*)ret); gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id); gpr_mu_unlock(&g_mu); return ret->id; } } int census_add_method_tag(census_op_id op_id, const char* method) { int ret = 0; census_trace_obj* trace = NULL; gpr_mu_lock(&g_mu); trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); if (trace == NULL) { ret = 1; } else { trace->method = gpr_strdup(method); } gpr_mu_unlock(&g_mu); return ret; } void census_tracing_print(census_op_id op_id, const char* anno_txt) { census_trace_obj* trace = NULL; gpr_mu_lock(&g_mu); trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); if (trace != NULL) { census_trace_annotation* anno = gpr_malloc(sizeof(census_trace_annotation)); anno->ts = gpr_now(GPR_CLOCK_REALTIME); { char* d = anno->txt; const char* s = anno_txt; int n = 0; for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) { *d++ = *s++; } *d = '\0'; } anno->next = trace->annotations; trace->annotations = anno; } gpr_mu_unlock(&g_mu); } void census_tracing_end_op(census_op_id op_id) { census_trace_obj* trace = NULL; gpr_mu_lock(&g_mu); trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); if (trace != NULL) { trace->rpc_stats.elapsed_time_ms = gpr_timespec_to_micros( gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), trace->ts)); gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us", op_id_2_uint64(&op_id), trace->method, trace->rpc_stats.elapsed_time_ms); census_ht_erase(g_trace_store, op_id_as_key(&op_id)); } gpr_mu_unlock(&g_mu); } void census_tracing_init(void) { init_mutex_once(); gpr_mu_lock(&g_mu); if (g_trace_store == NULL) { g_id = 1; g_trace_store = census_ht_create(&ht_opt); } else { gpr_log(GPR_ERROR, "Census trace store already initialized."); } gpr_mu_unlock(&g_mu); } void census_tracing_shutdown(void) { gpr_mu_lock(&g_mu); if (g_trace_store != NULL) { census_ht_destroy(g_trace_store); g_trace_store = NULL; } else { gpr_log(GPR_ERROR, "Census trace store is not initialized."); } gpr_mu_unlock(&g_mu); } void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); } void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); } census_trace_obj* census_get_trace_obj_locked(census_op_id op_id) { if (g_trace_store == NULL) { gpr_log(GPR_ERROR, "Census trace store is not initialized."); return NULL; } return (census_trace_obj*)census_ht_find(g_trace_store, op_id_as_key(&op_id)); } const char* census_get_trace_method_name(const census_trace_obj* trace) { return trace->method; } static census_trace_annotation* dup_annotation_chain( census_trace_annotation* from) { census_trace_annotation* ret = NULL; census_trace_annotation** to = &ret; for (; from != NULL; from = from->next) { *to = gpr_malloc(sizeof(census_trace_annotation)); memcpy(*to, from, sizeof(census_trace_annotation)); to = &(*to)->next; } return ret; } static census_trace_obj* trace_obj_dup(census_trace_obj* from) { census_trace_obj* to = NULL; GPR_ASSERT(from != NULL); to = gpr_malloc(sizeof(census_trace_obj)); to->id = from->id; to->ts = from->ts; to->rpc_stats = from->rpc_stats; to->method = gpr_strdup(from->method); to->annotations = dup_annotation_chain(from->annotations); return to; } census_trace_obj** census_get_active_ops(int* num_active_ops) { census_trace_obj** ret = NULL; gpr_mu_lock(&g_mu); if (g_trace_store != NULL) { size_t n = 0; census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n); *num_active_ops = (int)n; if (n != 0) { size_t i = 0; ret = gpr_malloc(sizeof(census_trace_obj*) * n); for (i = 0; i < n; i++) { ret[i] = trace_obj_dup((census_trace_obj*)all_kvs[i].v); } } gpr_free(all_kvs); } gpr_mu_unlock(&g_mu); return ret; } grpc-0.11.1/src/core/statistics/window_stats.h0000644000175000017500000001772612600663151021543 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H #define GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H #include /* Keep rolling sums of a user-defined statistic (containing a number of measurements) over a a number of time intervals ("windows"). For example, you can use a window_stats object to answer questions such as "Approximately how many RPCs/s did I receive over the past minute, and approximately how many bytes did I send out over that period?". The type of data to record, and the time intervals to keep are specified when creating the object via a call to census_window_stats_create(). A window's interval is divided into one or more "buckets"; the interval must be divisible by the number of buckets. Internally, these buckets control the granularity of window_stats' measurements. Increasing the number of buckets lets the object respond more quickly to changes in the overall rate of data added into the object, at the cost of additional memory usage. Here's some code which keeps one minute/hour measurements for two values (latency in seconds and bytes transferred), with each interval divided into 4 buckets. typedef struct my_stat { double latency; int bytes; } my_stat; void add_my_stat(void* base, const void* addme) { my_stat* b = (my_stat*)base; const my_stat* a = (const my_stat*)addme; b->latency += a->latency; b->bytes += a->bytes; } void add_proportion_my_stat(double p, void* base, const void* addme) { (my_stat*)result->latency += p * (const my_stat*)base->latency; (my_stat*)result->bytes += p * (const my_stat*)base->bytes; } #define kNumIntervals 2 #define kMinInterval 0 #define kHourInterval 1 #define kNumBuckets 4 const struct census_window_stats_stat_info kMyStatInfo = { sizeof(my_stat), NULL, add_my_stat, add_proportion_my_stat }; gpr_timespec intervals[kNumIntervals] = {{60, 0}, {3600, 0}}; my_stat stat; my_stat sums[kNumIntervals]; census_window_stats_sums result[kNumIntervals]; struct census_window_stats* stats = census_window_stats_create(kNumIntervals, intervals, kNumBuckets, &kMyStatInfo); // Record a new event, taking 15.3ms, transferring 1784 bytes. stat.latency = 0.153; stat.bytes = 1784; census_window_stats_add(stats, gpr_now(GPR_CLOCK_REALTIME), &stat); // Get sums and print them out result[kMinInterval].statistic = &sums[kMinInterval]; result[kHourInterval].statistic = &sums[kHourInterval]; census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), result); printf("%d events/min, average time %gs, average bytes %g\n", result[kMinInterval].count, (my_stat*)result[kMinInterval].statistic->latency / result[kMinInterval].count, (my_stat*)result[kMinInterval].statistic->bytes / result[kMinInterval].count ); printf("%d events/hr, average time %gs, average bytes %g\n", result[kHourInterval].count, (my_stat*)result[kHourInterval].statistic->latency / result[kHourInterval].count, (my_stat*)result[kHourInterval].statistic->bytes / result[kHourInterval].count ); */ /* Opaque structure for representing window_stats object */ struct census_window_stats; /* Information provided by API user on the information they want to record */ typedef struct census_window_stats_stat_info { /* Number of bytes in user-defined object. */ size_t stat_size; /* Function to initialize a user-defined statistics object. If this is set * to NULL, then the object will be zero-initialized. */ void (*stat_initialize)(void* stat); /* Function to add one user-defined statistics object ('addme') to 'base' */ void (*stat_add)(void* base, const void* addme); /* As for previous function, but only add a proportion 'p'. This API will currently only use 'p' values in the range [0,1], but other values are possible in the future, and should be supported. */ void (*stat_add_proportion)(double p, void* base, const void* addme); } census_window_stats_stat_info; /* Create a new window_stats object. 'nintervals' is the number of 'intervals', and must be >=1. 'granularity' is the number of buckets, with a larger number using more memory, but providing greater accuracy of results. 'granularity should be > 2. We also require that each interval be at least 10 * 'granularity' nanoseconds in size. 'stat_info' contains information about the statistic to be gathered. Intervals greater than ~192 years will be treated as essentially infinite in size. This function will GPR_ASSERT() if the object cannot be created or any of the parameters have invalid values. This function is thread-safe. */ struct census_window_stats* census_window_stats_create( int nintervals, const gpr_timespec intervals[], int granularity, const census_window_stats_stat_info* stat_info); /* Add a new measurement (in 'stat_value'), as of a given time ('when'). This function is thread-compatible. */ void census_window_stats_add(struct census_window_stats* wstats, const gpr_timespec when, const void* stat_value); /* Structure used to record a single intervals sum for a given statistic */ typedef struct census_window_stats_sum { /* Total count of samples. Note that because some internal interpolation is performed, the count of samples returned for each interval may not be an integral value. */ double count; /* Sum for statistic */ void* statistic; } census_window_stats_sums; /* Retrieve a set of all values stored in a window_stats object 'wstats'. The number of 'sums' MUST be the same as the number 'nintervals' used in census_window_stats_create(). This function is thread-compatible. */ void census_window_stats_get_sums(const struct census_window_stats* wstats, const gpr_timespec when, struct census_window_stats_sum sums[]); /* Destroy a window_stats object. Once this function has been called, the object will no longer be usable from any of the above functions (and calling them will most likely result in a NULL-pointer dereference or assertion failure). This function is thread-compatible. */ void census_window_stats_destroy(struct census_window_stats* wstats); #endif /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */ grpc-0.11.1/src/core/statistics/census_interface.h0000644000175000017500000000621412600663151022324 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H #define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H #include /* Maximum length of an individual census trace annotation. */ #define CENSUS_MAX_ANNOTATION_LENGTH 200 /* Structure of a census op id. Define as structure because 64bit integer is not available on every platform for C89. */ typedef struct census_op_id { gpr_uint32 upper; gpr_uint32 lower; } census_op_id; typedef struct census_rpc_stats census_rpc_stats; /* Initializes Census library. No-op if Census is already initialized. */ void census_init(void); /* Shutdown Census Library. */ void census_shutdown(void); /* Annotates grpc method name on a census_op_id. The method name has the format of /. Returns 0 iff op_id and method_name are all valid. op_id is valid after its creation and before calling census_tracing_end_op(). TODO(hongyu): Figure out valid characters set for service name and command name and document requirements here.*/ int census_add_method_tag(census_op_id op_id, const char* method_name); /* Annotates tracing information to a specific op_id. Up to CENSUS_MAX_ANNOTATION_LENGTH bytes are recorded. */ void census_tracing_print(census_op_id op_id, const char* annotation); /* Starts tracing for an RPC. Returns a locally unique census_op_id */ census_op_id census_tracing_start_op(void); /* Ends tracing. Calling this function will invalidate the input op_id. */ void census_tracing_end_op(census_op_id op_id); #endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H */ grpc-0.11.1/src/core/statistics/census_rpc_stats.h0000644000175000017500000000732312600663151022370 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H #define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H #include "src/core/statistics/census_interface.h" #include #ifdef __cplusplus extern "C" { #endif struct census_rpc_stats { gpr_uint64 cnt; gpr_uint64 rpc_error_cnt; gpr_uint64 app_error_cnt; double elapsed_time_ms; double api_request_bytes; double wire_request_bytes; double api_response_bytes; double wire_response_bytes; }; /* Creates an empty rpc stats object on heap. */ census_rpc_stats* census_rpc_stats_create_empty(void); typedef struct census_per_method_rpc_stats { const char* method; census_rpc_stats minute_stats; /* cumulative stats in the past minute */ census_rpc_stats hour_stats; /* cumulative stats in the past hour */ census_rpc_stats total_stats; /* cumulative stats from last gc */ } census_per_method_rpc_stats; typedef struct census_aggregated_rpc_stats { int num_entries; census_per_method_rpc_stats* stats; } census_aggregated_rpc_stats; /* Initializes an aggregated rpc stats object to an empty state. */ void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats* data); /* Records client side stats of a rpc. */ void census_record_rpc_client_stats(census_op_id op_id, const census_rpc_stats* stats); /* Records server side stats of a rpc. */ void census_record_rpc_server_stats(census_op_id op_id, const census_rpc_stats* stats); /* The following two functions are intended for inprocess query of per-service per-method stats from grpc implementations. */ /* Populates *data_map with server side aggregated per-service per-method stats. DO NOT CALL from outside of grpc code. */ void census_get_server_stats(census_aggregated_rpc_stats* data_map); /* Populates *data_map with client side aggregated per-service per-method stats. DO NOT CALL from outside of grpc code. */ void census_get_client_stats(census_aggregated_rpc_stats* data_map); void census_stats_store_init(void); void census_stats_store_shutdown(void); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H */ grpc-0.11.1/src/core/statistics/census_log.c0000644000175000017500000005316012600663151021142 0ustar apollockapollock/* * * 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. * */ /* Available log space is divided up in blocks of CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the following three data structures: - Free blocks (free_block_list) - Blocks with unread data (dirty_block_list) - Blocks currently attached to cores (core_local_blocks[]) census_log_start_write() moves a block from core_local_blocks[] to the end of dirty_block_list when block: - is out-of-space OR - has an incomplete record (an incomplete record occurs when a thread calls census_log_start_write() and is context-switched before calling census_log_end_write() So, blocks in dirty_block_list are ordered, from oldest to newest, by time when block is detached from the core. census_log_read_next() first iterates over dirty_block_list and then core_local_blocks[]. It moves completely read blocks from dirty_block_list to free_block_list. Blocks in core_local_blocks[] are not freed, even when completely read. If log is configured to discard old records and free_block_list is empty, census_log_start_write() iterates over dirty_block_list to allocate a new block. It moves the oldest available block (no pending read/write) to core_local_blocks[]. core_local_block_struct is used to implement a map from core id to the block associated with that core. This mapping is advisory. It is possible that the block returned by this mapping is no longer associated with that core. This mapping is updated, lazily, by census_log_start_write(). Locking in block struct: Exclusive g_log.lock must be held before calling any functions operatong on block structs except census_log_start_write() and census_log_end_write(). Writes to a block are serialized via writer_lock. census_log_start_write() acquires this lock and census_log_end_write() releases it. On failure to acquire the lock, writer allocates a new block for the current core and updates core_local_block accordingly. Simultaneous read and write access is allowed. Reader can safely read up to committed bytes (bytes_committed). reader_lock protects the block, currently being read, from getting recycled. start_read() acquires reader_lock and end_read() releases the lock. Read/write access to a block is disabled via try_disable_access(). It returns with both writer_lock and reader_lock held. These locks are subsequently released by enable_access() to enable access to the block. A note on naming: Most function/struct names are prepended by cl_ (shorthand for census_log). Further, functions that manipulate structures include the name of the structure, which will be passed as the first argument. E.g. cl_block_initialize() will initialize a cl_block. */ #include "src/core/statistics/census_log.h" #include #include #include #include #include #include #include #include /* End of platform specific code */ typedef struct census_log_block_list_struct { struct census_log_block_list_struct* next; struct census_log_block_list_struct* prev; struct census_log_block* block; } cl_block_list_struct; typedef struct census_log_block { /* Pointer to underlying buffer */ char* buffer; gpr_atm writer_lock; gpr_atm reader_lock; /* Keeps completely written bytes. Declared atomic because accessed simultaneously by reader and writer. */ gpr_atm bytes_committed; /* Bytes already read */ gpr_int32 bytes_read; /* Links for list */ cl_block_list_struct link; /* We want this structure to be cacheline aligned. We assume the following sizes for the various parts on 32/64bit systems: type 32b size 64b size char* 4 8 3x gpr_atm 12 24 gpr_int32 4 8 (assumes padding) cl_block_list_struct 12 24 TOTAL 32 64 Depending on the size of our cacheline and the architecture, we selectively add char buffering to this structure. The size is checked via assert in census_log_initialize(). */ #if defined(GPR_ARCH_64) #define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64) #else #if defined(GPR_ARCH_32) #define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32) #else #error "Unknown architecture" #endif #endif #if CL_BLOCK_PAD_SIZE > 0 char padding[CL_BLOCK_PAD_SIZE]; #endif } cl_block; /* A list of cl_blocks, doubly-linked through cl_block::link. */ typedef struct census_log_block_list { gpr_int32 count; /* Number of items in list. */ cl_block_list_struct ht; /* head/tail of linked list. */ } cl_block_list; /* Cacheline aligned block pointers to avoid false sharing. Block pointer must be initialized via set_block(), before calling other functions */ typedef struct census_log_core_local_block { gpr_atm block; /* Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 */ #if defined(GPR_ARCH_64) #define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8) #else #if defined(GPR_ARCH_32) #define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4) #else #error "Unknown architecture" #endif #endif #if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0 char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE]; #endif } cl_core_local_block; struct census_log { int discard_old_records; /* Number of cores (aka hardware-contexts) */ unsigned num_cores; /* number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log */ gpr_int32 num_blocks; cl_block* blocks; /* Block metadata. */ cl_core_local_block* core_local_blocks; /* Keeps core to block mappings. */ gpr_mu lock; int initialized; /* has log been initialized? */ /* Keeps the state of the reader iterator. A value of 0 indicates that iterator has reached the end. census_log_init_reader() resets the value to num_core to restart iteration. */ gpr_uint32 read_iterator_state; /* Points to the block being read. If non-NULL, the block is locked for reading (block_being_read_->reader_lock is held). */ cl_block* block_being_read; /* A non-zero value indicates that log is full. */ gpr_atm is_full; char* buffer; cl_block_list free_block_list; cl_block_list dirty_block_list; gpr_atm out_of_space_count; }; /* Single internal log */ static struct census_log g_log; /* Functions that operate on an atomic memory location used as a lock */ /* Returns non-zero if lock is acquired */ static int cl_try_lock(gpr_atm* lock) { return gpr_atm_acq_cas(lock, 0, 1); } static void cl_unlock(gpr_atm* lock) { gpr_atm_rel_store(lock, 0); } /* Functions that operate on cl_core_local_block's */ static void cl_core_local_block_set_block(cl_core_local_block* clb, cl_block* block) { gpr_atm_rel_store(&clb->block, (gpr_atm)block); } static cl_block* cl_core_local_block_get_block(cl_core_local_block* clb) { return (cl_block*)gpr_atm_acq_load(&clb->block); } /* Functions that operate on cl_block_list_struct's */ static void cl_block_list_struct_initialize(cl_block_list_struct* bls, cl_block* block) { bls->next = bls->prev = bls; bls->block = block; } /* Functions that operate on cl_block_list's */ static void cl_block_list_initialize(cl_block_list* list) { list->count = 0; cl_block_list_struct_initialize(&list->ht, NULL); } /* Returns head of *this, or NULL if empty. */ static cl_block* cl_block_list_head(cl_block_list* list) { return list->ht.next->block; } /* Insert element *e after *pos. */ static void cl_block_list_insert(cl_block_list* list, cl_block_list_struct* pos, cl_block_list_struct* e) { list->count++; e->next = pos->next; e->prev = pos; e->next->prev = e; e->prev->next = e; } /* Insert block at the head of the list */ static void cl_block_list_insert_at_head(cl_block_list* list, cl_block* block) { cl_block_list_insert(list, &list->ht, &block->link); } /* Insert block at the tail of the list */ static void cl_block_list_insert_at_tail(cl_block_list* list, cl_block* block) { cl_block_list_insert(list, list->ht.prev, &block->link); } /* Removes block *b. Requires *b be in the list. */ static void cl_block_list_remove(cl_block_list* list, cl_block* b) { list->count--; b->link.next->prev = b->link.prev; b->link.prev->next = b->link.next; } /* Functions that operate on cl_block's */ static void cl_block_initialize(cl_block* block, char* buffer) { block->buffer = buffer; gpr_atm_rel_store(&block->writer_lock, 0); gpr_atm_rel_store(&block->reader_lock, 0); gpr_atm_rel_store(&block->bytes_committed, 0); block->bytes_read = 0; cl_block_list_struct_initialize(&block->link, block); } /* Guards against exposing partially written buffer to the reader. */ static void cl_block_set_bytes_committed(cl_block* block, gpr_int32 bytes_committed) { gpr_atm_rel_store(&block->bytes_committed, bytes_committed); } static gpr_int32 cl_block_get_bytes_committed(cl_block* block) { return gpr_atm_acq_load(&block->bytes_committed); } /* Tries to disable future read/write access to this block. Succeeds if: - no in-progress write AND - no in-progress read AND - 'discard_data' set to true OR no unread data On success, clears the block state and returns with writer_lock_ and reader_lock_ held. These locks are released by a subsequent cl_block_access_enable() call. */ static int cl_block_try_disable_access(cl_block* block, int discard_data) { if (!cl_try_lock(&block->writer_lock)) { return 0; } if (!cl_try_lock(&block->reader_lock)) { cl_unlock(&block->writer_lock); return 0; } if (!discard_data && (block->bytes_read != cl_block_get_bytes_committed(block))) { cl_unlock(&block->reader_lock); cl_unlock(&block->writer_lock); return 0; } cl_block_set_bytes_committed(block, 0); block->bytes_read = 0; return 1; } static void cl_block_enable_access(cl_block* block) { cl_unlock(&block->reader_lock); cl_unlock(&block->writer_lock); } /* Returns with writer_lock held. */ static void* cl_block_start_write(cl_block* block, size_t size) { gpr_int32 bytes_committed; if (!cl_try_lock(&block->writer_lock)) { return NULL; } bytes_committed = cl_block_get_bytes_committed(block); if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) { cl_unlock(&block->writer_lock); return NULL; } return block->buffer + bytes_committed; } /* Releases writer_lock and increments committed bytes by 'bytes_written'. 'bytes_written' must be <= 'size' specified in the corresponding StartWrite() call. This function is thread-safe. */ static void cl_block_end_write(cl_block* block, size_t bytes_written) { cl_block_set_bytes_committed( block, cl_block_get_bytes_committed(block) + bytes_written); cl_unlock(&block->writer_lock); } /* Returns a pointer to the first unread byte in buffer. The number of bytes available are returned in 'bytes_available'. Acquires reader lock that is released by a subsequent cl_block_end_read() call. Returns NULL if: - read in progress - no data available */ static void* cl_block_start_read(cl_block* block, size_t* bytes_available) { void* record; if (!cl_try_lock(&block->reader_lock)) { return NULL; } /* bytes_committed may change from under us. Use bytes_available to update bytes_read below. */ *bytes_available = cl_block_get_bytes_committed(block) - block->bytes_read; if (*bytes_available == 0) { cl_unlock(&block->reader_lock); return NULL; } record = block->buffer + block->bytes_read; block->bytes_read += *bytes_available; return record; } static void cl_block_end_read(cl_block* block) { cl_unlock(&block->reader_lock); } /* Internal functions operating on g_log */ /* Allocates a new free block (or recycles an available dirty block if log is configured to discard old records). Returns NULL if out-of-space. */ static cl_block* cl_allocate_block(void) { cl_block* block = cl_block_list_head(&g_log.free_block_list); if (block != NULL) { cl_block_list_remove(&g_log.free_block_list, block); return block; } if (!g_log.discard_old_records) { /* No free block and log is configured to keep old records. */ return NULL; } /* Recycle dirty block. Start from the oldest. */ for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL; block = block->link.next->block) { if (cl_block_try_disable_access(block, 1 /* discard data */)) { cl_block_list_remove(&g_log.dirty_block_list, block); return block; } } return NULL; } /* Allocates a new block and updates core id => block mapping. 'old_block' points to the block that the caller thinks is attached to 'core_id'. 'old_block' may be NULL. Returns non-zero if: - allocated a new block OR - 'core_id' => 'old_block' mapping changed (another thread allocated a block before lock was acquired). */ static int cl_allocate_core_local_block(gpr_int32 core_id, cl_block* old_block) { /* Now that we have the lock, check if core-local mapping has changed. */ cl_core_local_block* core_local_block = &g_log.core_local_blocks[core_id]; cl_block* block = cl_core_local_block_get_block(core_local_block); if ((block != NULL) && (block != old_block)) { return 1; } if (block != NULL) { cl_core_local_block_set_block(core_local_block, NULL); cl_block_list_insert_at_tail(&g_log.dirty_block_list, block); } block = cl_allocate_block(); if (block == NULL) { gpr_atm_rel_store(&g_log.is_full, 1); return 0; } cl_core_local_block_set_block(core_local_block, block); cl_block_enable_access(block); return 1; } static cl_block* cl_get_block(void* record) { gpr_uintptr p = (gpr_uintptr)((char*)record - g_log.buffer); gpr_uintptr index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE; return &g_log.blocks[index]; } /* Gets the next block to read and tries to free 'prev' block (if not NULL). Returns NULL if reached the end. */ static cl_block* cl_next_block_to_read(cl_block* prev) { cl_block* block = NULL; if (g_log.read_iterator_state == g_log.num_cores) { /* We are traversing dirty list; find the next dirty block. */ if (prev != NULL) { /* Try to free the previous block if there is no unread data. This block may have unread data if previously incomplete record completed between read_next() calls. */ block = prev->link.next->block; if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) { cl_block_list_remove(&g_log.dirty_block_list, prev); cl_block_list_insert_at_head(&g_log.free_block_list, prev); gpr_atm_rel_store(&g_log.is_full, 0); } } else { block = cl_block_list_head(&g_log.dirty_block_list); } if (block != NULL) { return block; } /* We are done with the dirty list; moving on to core-local blocks. */ } while (g_log.read_iterator_state > 0) { g_log.read_iterator_state--; block = cl_core_local_block_get_block( &g_log.core_local_blocks[g_log.read_iterator_state]); if (block != NULL) { return block; } } return NULL; } /* External functions: primary stats_log interface */ void census_log_initialize(size_t size_in_mb, int discard_old_records) { gpr_int32 ix; /* Check cacheline alignment. */ GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0); GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0); GPR_ASSERT(!g_log.initialized); g_log.discard_old_records = discard_old_records; g_log.num_cores = gpr_cpu_num_cores(); /* Ensure at least as many blocks as there are cores. */ g_log.num_blocks = GPR_MAX( g_log.num_cores, (size_in_mb << 20) >> CENSUS_LOG_2_MAX_RECORD_SIZE); gpr_mu_init(&g_log.lock); g_log.read_iterator_state = 0; g_log.block_being_read = NULL; gpr_atm_rel_store(&g_log.is_full, 0); g_log.core_local_blocks = (cl_core_local_block*)gpr_malloc_aligned( g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG); memset(g_log.core_local_blocks, 0, g_log.num_cores * sizeof(cl_core_local_block)); g_log.blocks = (cl_block*)gpr_malloc_aligned( g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG); memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block)); g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); cl_block_list_initialize(&g_log.free_block_list); cl_block_list_initialize(&g_log.dirty_block_list); for (ix = 0; ix < g_log.num_blocks; ++ix) { cl_block* block = g_log.blocks + ix; cl_block_initialize(block, g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * ix)); cl_block_try_disable_access(block, 1 /* discard data */); cl_block_list_insert_at_tail(&g_log.free_block_list, block); } gpr_atm_rel_store(&g_log.out_of_space_count, 0); g_log.initialized = 1; } void census_log_shutdown(void) { GPR_ASSERT(g_log.initialized); gpr_mu_destroy(&g_log.lock); gpr_free_aligned(g_log.core_local_blocks); g_log.core_local_blocks = NULL; gpr_free_aligned(g_log.blocks); g_log.blocks = NULL; gpr_free(g_log.buffer); g_log.buffer = NULL; g_log.initialized = 0; } void* census_log_start_write(size_t size) { /* Used to bound number of times block allocation is attempted. */ gpr_int32 attempts_remaining = g_log.num_blocks; /* TODO(aveitch): move this inside the do loop when current_cpu is fixed */ gpr_int32 core_id = gpr_cpu_current_cpu(); GPR_ASSERT(g_log.initialized); if (size > CENSUS_LOG_MAX_RECORD_SIZE) { return NULL; } do { int allocated; void* record = NULL; cl_block* block = cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]); if (block && (record = cl_block_start_write(block, size))) { return record; } /* Need to allocate a new block. We are here if: - No block associated with the core OR - Write in-progress on the block OR - block is out of space */ if (gpr_atm_acq_load(&g_log.is_full)) { gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); return NULL; } gpr_mu_lock(&g_log.lock); allocated = cl_allocate_core_local_block(core_id, block); gpr_mu_unlock(&g_log.lock); if (!allocated) { gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); return NULL; } } while (attempts_remaining--); /* Give up. */ gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); return NULL; } void census_log_end_write(void* record, size_t bytes_written) { GPR_ASSERT(g_log.initialized); cl_block_end_write(cl_get_block(record), bytes_written); } void census_log_init_reader(void) { GPR_ASSERT(g_log.initialized); gpr_mu_lock(&g_log.lock); /* If a block is locked for reading unlock it. */ if (g_log.block_being_read != NULL) { cl_block_end_read(g_log.block_being_read); g_log.block_being_read = NULL; } g_log.read_iterator_state = g_log.num_cores; gpr_mu_unlock(&g_log.lock); } const void* census_log_read_next(size_t* bytes_available) { GPR_ASSERT(g_log.initialized); gpr_mu_lock(&g_log.lock); if (g_log.block_being_read != NULL) { cl_block_end_read(g_log.block_being_read); } do { g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read); if (g_log.block_being_read != NULL) { void* record = cl_block_start_read(g_log.block_being_read, bytes_available); if (record != NULL) { gpr_mu_unlock(&g_log.lock); return record; } } } while (g_log.block_being_read != NULL); gpr_mu_unlock(&g_log.lock); return NULL; } size_t census_log_remaining_space(void) { size_t space; GPR_ASSERT(g_log.initialized); gpr_mu_lock(&g_log.lock); if (g_log.discard_old_records) { /* Remaining space is not meaningful; just return the entire log space. */ space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE; } else { space = g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE; } gpr_mu_unlock(&g_log.lock); return space; } int census_log_out_of_space_count(void) { GPR_ASSERT(g_log.initialized); return gpr_atm_acq_load(&g_log.out_of_space_count); } grpc-0.11.1/src/core/statistics/census_init.c0000644000175000017500000000360512600663151021323 0ustar apollockapollock/* * * 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/statistics/census_interface.h" #include #include "src/core/statistics/census_rpc_stats.h" #include "src/core/statistics/census_tracing.h" void census_init(void) { census_tracing_init(); census_stats_store_init(); } void census_shutdown(void) { census_stats_store_shutdown(); census_tracing_shutdown(); } grpc-0.11.1/src/core/statistics/window_stats.c0000644000175000017500000003021712600663151021524 0ustar apollockapollock/* * * 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/statistics/window_stats.h" #include #include #include #include #include #include #include /* typedefs make typing long names easier. Use cws (for census_window_stats) */ typedef census_window_stats_stat_info cws_stat_info; typedef struct census_window_stats_sum cws_sum; /* Each interval is composed of a number of buckets, which hold a count of entries and a single statistic */ typedef struct census_window_stats_bucket { gpr_int64 count; void* statistic; } cws_bucket; /* Each interval has a set of buckets, and the variables needed to keep track of their current state */ typedef struct census_window_stats_interval_stats { /* The buckets. There will be 'granularity' + 1 of these. */ cws_bucket* buckets; /* Index of the bucket containing the smallest time interval. */ int bottom_bucket; /* The smallest time storable in the current window. */ gpr_int64 bottom; /* The largest time storable in the current window + 1ns */ gpr_int64 top; /* The width of each bucket in ns. */ gpr_int64 width; } cws_interval_stats; typedef struct census_window_stats { /* Number of intervals. */ int nintervals; /* Number of buckets in each interval. 'granularity' + 1. */ int nbuckets; /* Record of stat_info. */ cws_stat_info stat_info; /* Stats for each interval. */ cws_interval_stats* interval_stats; /* The time the newset stat was recorded. */ gpr_int64 newest_time; } window_stats; /* Calculate an actual bucket index from a logical index 'IDX'. Other parameters supply information on the interval struct and overall stats. */ #define BUCKET_IDX(IS, IDX, WSTATS) \ ((IS->bottom_bucket + (IDX)) % WSTATS->nbuckets) /* The maximum seconds value we can have in a valid timespec. More than this will result in overflow in timespec_to_ns(). This works out to ~292 years. TODO: consider using doubles instead of int64. */ static gpr_int64 max_seconds = (GPR_INT64_MAX - GPR_NS_PER_SEC) / GPR_NS_PER_SEC; static gpr_int64 timespec_to_ns(const gpr_timespec ts) { if (ts.tv_sec > max_seconds) { return GPR_INT64_MAX - 1; } return (gpr_int64)ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec; } static void cws_initialize_statistic(void* statistic, const cws_stat_info* stat_info) { if (stat_info->stat_initialize == NULL) { memset(statistic, 0, stat_info->stat_size); } else { stat_info->stat_initialize(statistic); } } /* Create and initialize a statistic */ static void* cws_create_statistic(const cws_stat_info* stat_info) { void* stat = gpr_malloc(stat_info->stat_size); cws_initialize_statistic(stat, stat_info); return stat; } window_stats* census_window_stats_create(int nintervals, const gpr_timespec intervals[], int granularity, const cws_stat_info* stat_info) { window_stats* ret; int i; /* validate inputs */ GPR_ASSERT(nintervals > 0 && granularity > 2 && intervals != NULL && stat_info != NULL); for (i = 0; i < nintervals; i++) { gpr_int64 ns = timespec_to_ns(intervals[i]); GPR_ASSERT(intervals[i].tv_sec >= 0 && intervals[i].tv_nsec >= 0 && intervals[i].tv_nsec < GPR_NS_PER_SEC && ns >= 100 && granularity * 10 <= ns); } /* Allocate and initialize relevant data structures */ ret = (window_stats*)gpr_malloc(sizeof(window_stats)); ret->nintervals = nintervals; ret->nbuckets = granularity + 1; ret->stat_info = *stat_info; ret->interval_stats = (cws_interval_stats*)gpr_malloc(nintervals * sizeof(cws_interval_stats)); for (i = 0; i < nintervals; i++) { gpr_int64 size_ns = timespec_to_ns(intervals[i]); cws_interval_stats* is = ret->interval_stats + i; cws_bucket* buckets = is->buckets = (cws_bucket*)gpr_malloc(ret->nbuckets * sizeof(cws_bucket)); int b; for (b = 0; b < ret->nbuckets; b++) { buckets[b].statistic = cws_create_statistic(stat_info); buckets[b].count = 0; } is->bottom_bucket = 0; is->bottom = 0; is->width = size_ns / granularity; /* Check for possible overflow issues, and maximize interval size if the user requested something large enough. */ if ((GPR_INT64_MAX - is->width) > size_ns) { is->top = size_ns + is->width; } else { is->top = GPR_INT64_MAX; is->width = GPR_INT64_MAX / (granularity + 1); } /* If size doesn't divide evenly, we can have a width slightly too small; better to have it slightly large. */ if ((size_ns - (granularity + 1) * is->width) > 0) { is->width += 1; } } ret->newest_time = 0; return ret; } /* When we try adding a measurement above the current interval range, we need to "shift" the buckets sufficiently to cover the new range. */ static void cws_shift_buckets(const window_stats* wstats, cws_interval_stats* is, gpr_int64 when_ns) { int i; /* number of bucket time widths to "shift" */ int shift; /* number of buckets to clear */ int nclear; GPR_ASSERT(when_ns >= is->top); /* number of bucket time widths to "shift" */ shift = ((when_ns - is->top) / is->width) + 1; /* number of buckets to clear - limited by actual number of buckets */ nclear = GPR_MIN(shift, wstats->nbuckets); for (i = 0; i < nclear; i++) { int b = BUCKET_IDX(is, i, wstats); is->buckets[b].count = 0; cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info); } /* adjust top/bottom times and current bottom bucket */ is->bottom_bucket = BUCKET_IDX(is, shift, wstats); is->top += shift * is->width; is->bottom += shift * is->width; } void census_window_stats_add(window_stats* wstats, const gpr_timespec when, const void* stat_value) { int i; gpr_int64 when_ns = timespec_to_ns(when); GPR_ASSERT(wstats->interval_stats != NULL); for (i = 0; i < wstats->nintervals; i++) { cws_interval_stats* is = wstats->interval_stats + i; cws_bucket* bucket; if (when_ns < is->bottom) { /* Below smallest time in interval: drop */ continue; } if (when_ns >= is->top) { /* above limit: shift buckets */ cws_shift_buckets(wstats, is, when_ns); } /* Add the stat. */ GPR_ASSERT(is->bottom <= when_ns && when_ns < is->top); bucket = is->buckets + BUCKET_IDX(is, (when_ns - is->bottom) / is->width, wstats); bucket->count++; wstats->stat_info.stat_add(bucket->statistic, stat_value); } if (when_ns > wstats->newest_time) { wstats->newest_time = when_ns; } } /* Add a specific bucket contents to an accumulating total. */ static void cws_add_bucket_to_sum(cws_sum* sum, const cws_bucket* bucket, const cws_stat_info* stat_info) { sum->count += bucket->count; stat_info->stat_add(sum->statistic, bucket->statistic); } /* Add a proportion to an accumulating sum. */ static void cws_add_proportion_to_sum(double p, cws_sum* sum, const cws_bucket* bucket, const cws_stat_info* stat_info) { sum->count += p * bucket->count; stat_info->stat_add_proportion(p, sum->statistic, bucket->statistic); } void census_window_stats_get_sums(const window_stats* wstats, const gpr_timespec when, cws_sum sums[]) { int i; gpr_int64 when_ns = timespec_to_ns(when); GPR_ASSERT(wstats->interval_stats != NULL); for (i = 0; i < wstats->nintervals; i++) { int when_bucket; int new_bucket; double last_proportion = 1.0; double bottom_proportion; cws_interval_stats* is = wstats->interval_stats + i; cws_sum* sum = sums + i; sum->count = 0; cws_initialize_statistic(sum->statistic, &wstats->stat_info); if (when_ns < is->bottom) { continue; } if (when_ns >= is->top) { cws_shift_buckets(wstats, is, when_ns); } /* Calculating the appropriate amount of which buckets to use can get complicated. Essentially there are two cases: 1) if the "top" bucket (new_bucket, where the newest additions to the stats recorded are entered) corresponds to 'when', then we need to take a proportion of it - (if when < newest_time) or the full thing. We also (possibly) need to take a corresponding proportion of the bottom bucket. 2) Other cases, we just take a straight proportion. */ when_bucket = (when_ns - is->bottom) / is->width; new_bucket = (wstats->newest_time - is->bottom) / is->width; if (new_bucket == when_bucket) { gpr_int64 bottom_bucket_time = is->bottom + when_bucket * is->width; if (when_ns < wstats->newest_time) { last_proportion = (double)(when_ns - bottom_bucket_time) / (double)(wstats->newest_time - bottom_bucket_time); bottom_proportion = (double)(is->width - (when_ns - bottom_bucket_time)) / is->width; } else { bottom_proportion = (double)(is->width - (wstats->newest_time - bottom_bucket_time)) / is->width; } } else { last_proportion = (double)(when_ns + 1 - is->bottom - when_bucket * is->width) / is->width; bottom_proportion = 1.0 - last_proportion; } cws_add_proportion_to_sum(last_proportion, sum, is->buckets + BUCKET_IDX(is, when_bucket, wstats), &wstats->stat_info); if (when_bucket != 0) { /* last bucket isn't also bottom bucket */ int b; /* Add all of "bottom" bucket if we are looking at a subset of the full interval, or a proportion if we are adding full interval. */ cws_add_proportion_to_sum( (when_bucket == wstats->nbuckets - 1 ? bottom_proportion : 1.0), sum, is->buckets + is->bottom_bucket, &wstats->stat_info); /* Add all the remaining buckets (everything but top and bottom). */ for (b = 1; b < when_bucket; b++) { cws_add_bucket_to_sum(sum, is->buckets + BUCKET_IDX(is, b, wstats), &wstats->stat_info); } } } } void census_window_stats_destroy(window_stats* wstats) { int i; GPR_ASSERT(wstats->interval_stats != NULL); for (i = 0; i < wstats->nintervals; i++) { int b; for (b = 0; b < wstats->nbuckets; b++) { gpr_free(wstats->interval_stats[i].buckets[b].statistic); } gpr_free(wstats->interval_stats[i].buckets); } gpr_free(wstats->interval_stats); /* Ensure any use-after free triggers assert. */ wstats->interval_stats = NULL; gpr_free(wstats); } grpc-0.11.1/src/core/statistics/census_tracing.h0000644000175000017500000000733612600663151022021 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H #define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H #include #include "src/core/statistics/census_rpc_stats.h" /* WARNING: The data structures and APIs provided by this file are for GRPC library's internal use ONLY. They might be changed in backward-incompatible ways and are not subject to any deprecation policy. They are not recommended for external use. */ #ifdef __cplusplus extern "C" { #endif /* Struct for a trace annotation. */ typedef struct census_trace_annotation { gpr_timespec ts; /* timestamp of the annotation */ char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */ struct census_trace_annotation* next; } census_trace_annotation; typedef struct census_trace_obj { census_op_id id; gpr_timespec ts; census_rpc_stats rpc_stats; char* method; census_trace_annotation* annotations; } census_trace_obj; /* Deletes trace object. */ void census_trace_obj_destroy(census_trace_obj* obj); /* Initializes trace store. This function is thread safe. */ void census_tracing_init(void); /* Shutsdown trace store. This function is thread safe. */ void census_tracing_shutdown(void); /* Gets trace obj corresponding to the input op_id. Returns NULL if trace store is not initialized or trace obj is not found. Requires trace store being locked before calling this function. */ census_trace_obj* census_get_trace_obj_locked(census_op_id op_id); /* The following two functions acquire and release the trace store global lock. They are for census internal use only. */ void census_internal_lock_trace_store(void); void census_internal_unlock_trace_store(void); /* Gets method name associated with the input trace object. */ const char* census_get_trace_method_name(const census_trace_obj* trace); /* Returns an array of pointers to trace objects of currently active operations and fills in number of active operations. Returns NULL if there are no active operations. Caller owns the returned objects. */ census_trace_obj** census_get_active_ops(int* num_active_ops); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H */ grpc-0.11.1/src/core/census/0000755000175000017500000000000012600663151015736 5ustar apollockapollockgrpc-0.11.1/src/core/census/README.md0000644000175000017500000000574612600663151017231 0ustar apollockapollock # Census - a resource measurement and tracing system This directory contains code for Census, which will ultimately provide the following features for any gRPC-using system: * A [dapper](http://research.google.com/pubs/pub36356.html)-like tracing system, enabling tracing across a distributed infrastructure. * RPC statistics and measurements for key metrics, such as latency, bytes transferred, number of errors etc. * Resource measurement framework which can be used for measuring custom metrics. Through the use of [tags](#Tags), these can be broken down across the entire distributed stack. * Easy integration of the above with [Google Cloud Trace](https://cloud.google.com/tools/cloud-trace) and [Google Cloud Monitoring](https://cloud.google.com/monitoring/). ## Concepts ### Context ### Operations ### Tags ### Metrics ## API ### Internal/RPC API ### External/Client API ### RPC API ## Files in this directory Note that files and functions in this directory can be split into two categories: * Files that define core census library functions. Functions etc. in these files are named census\_\*, and constitute the core census library functionality. At some time in the future, these will become a standalone library. * Files that define functions etc. that provide a convenient interface between grpc and the core census functionality. These files are all named grpc\_\*.{c,h}, and define function names beginning with grpc\_census\_\*. grpc-0.11.1/src/core/census/grpc_filter.h0000644000175000017500000000376612600663151020423 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H #define GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H #include "src/core/channel/channel_stack.h" /* Census filters: provides tracing and stats collection functionalities. It needs to reside right below the surface filter in the channel stack. */ extern const grpc_channel_filter grpc_client_census_filter; extern const grpc_channel_filter grpc_server_census_filter; #endif /* GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H */ grpc-0.11.1/src/core/census/aggregation.h0000644000175000017500000000602612600663151020402 0ustar apollockapollock/* * * 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 #ifndef GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H #define GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H /** Structure used to describe an aggregation type. */ struct census_aggregation_ops { /* Create a new aggregation. The pointer returned can be used in future calls to clone(), free(), record(), data() and reset(). */ void *(*create)(const void *create_arg); /* Make a copy of an aggregation created by create() */ void *(*clone)(const void *aggregation); /* Destroy an aggregation created by create() */ void (*free)(void *aggregation); /* Record a new value against aggregation. */ void (*record)(void *aggregation, double value); /* Return current aggregation data. The caller must cast this object into the correct type for the aggregation result. The object returned can be freed by using free_data(). */ void *(*data)(const void *aggregation); /* free data returned by data() */ void (*free_data)(void *data); /* Reset an aggregation to default (zero) values. */ void (*reset)(void *aggregation); /* Merge 'from' aggregation into 'to'. Both aggregations must be compatible */ void (*merge)(void *to, const void *from); /* Fill buffer with printable string version of aggregation contents. For debugging only. Returns the number of bytes added to buffer (a value == n implies the buffer was of insufficient size). */ size_t (*print)(const void *aggregation, char *buffer, size_t n); }; #endif /* GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H */ grpc-0.11.1/src/core/census/context.h0000644000175000017500000000410012600663151017566 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H #define GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H #include /* census_context is the in-memory representation of information needed to * maintain tracing, RPC statistics and resource usage information. */ struct census_context { gpr_uint64 op_id; /* Operation identifier - unique per-context */ gpr_uint64 trace_id; /* Globally unique trace identifier */ /* TODO(aveitch) Add census tags: const census_tag_set *tags; */ }; #endif /* GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H */ grpc-0.11.1/src/core/census/initialize.c0000644000175000017500000000411512600663151020244 0ustar apollockapollock/* * * 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 static int features_enabled = CENSUS_FEATURE_NONE; int census_initialize(int features) { if (features_enabled != CENSUS_FEATURE_NONE) { return 1; } if (features != CENSUS_FEATURE_NONE) { return 1; } else { features_enabled = features; return 0; } } void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; } int census_supported(void) { /* TODO(aveitch): improve this as we implement features... */ return CENSUS_FEATURE_NONE; } int census_enabled(void) { return features_enabled; } grpc-0.11.1/src/core/census/operation.c0000644000175000017500000000500312600663151020100 0ustar apollockapollock/* * 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 /* TODO(aveitch): These are all placeholder implementations. */ census_timestamp census_start_rpc_op_timestamp(void) { census_timestamp ct; /* TODO(aveitch): assumes gpr_timespec implementation of census_timestamp. */ ct.ts = gpr_now(GPR_CLOCK_MONOTONIC); return ct; } census_context *census_start_client_rpc_op( const census_context *context, gpr_int64 rpc_name_id, const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, const census_timestamp *start_time) { return NULL; } census_context *census_start_server_rpc_op( const char *buffer, gpr_int64 rpc_name_id, const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, census_timestamp *start_time) { return NULL; } census_context *census_start_op(census_context *context, const char *family, const char *name, int trace_mask) { return NULL; } void census_end_op(census_context *context, int status) {} grpc-0.11.1/src/core/census/grpc_context.c0000644000175000017500000000377312600663151020613 0ustar apollockapollock/* * * 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 #include #include "src/core/surface/call.h" void grpc_census_call_set_context(grpc_call *call, census_context *context) { if (census_enabled() == CENSUS_FEATURE_NONE) { return; } if (context != NULL) { grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL); } } census_context *grpc_census_call_get_context(grpc_call *call) { return (census_context *)grpc_call_context_get(call, GRPC_CONTEXT_TRACING); } grpc-0.11.1/src/core/census/rpc_metric_id.h0000644000175000017500000000431712600663151020717 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef CENSUS_RPC_METRIC_ID_H #define CENSUS_RPC_METRIC_ID_H /* Metric ID's used for RPC measurements. */ /* Count of client requests sent. */ #define CENSUS_METRIC_RPC_CLIENT_REQUESTS ((gpr_uint32)0) /* Count of server requests sent. */ #define CENSUS_METRIC_RPC_SERVER_REQUESTS ((gpr_uint32)1) /* Client error counts. */ #define CENSUS_METRIC_RPC_CLIENT_ERRORS ((gpr_uint32)2) /* Server error counts. */ #define CENSUS_METRIC_RPC_SERVER_ERRORS ((gpr_uint32)3) /* Client side request latency. */ #define CENSUS_METRIC_RPC_CLIENT_LATENCY ((gpr_uint32)4) /* Server side request latency. */ #define CENSUS_METRIC_RPC_SERVER_LATENCY ((gpr_uint32)5) #endif /* CENSUS_RPC_METRIC_ID_H */ grpc-0.11.1/src/core/census/grpc_filter.c0000644000175000017500000001540212600663151020404 0ustar apollockapollock/* * * 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/census/grpc_filter.h" #include #include #include "src/core/channel/channel_stack.h" #include "src/core/channel/noop_filter.h" #include "src/core/statistics/census_interface.h" #include "src/core/statistics/census_rpc_stats.h" #include #include #include #include #include typedef struct call_data { census_op_id op_id; census_context* ctxt; gpr_timespec start_ts; int error; /* recv callback */ grpc_stream_op_buffer* recv_ops; grpc_iomgr_closure* on_done_recv; } call_data; typedef struct channel_data { grpc_mdstr* path_str; /* pointer to meta data str with key == ":path" */ } channel_data; static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb, call_data* calld, channel_data* chand) { grpc_linked_mdelem* m; size_t i; for (i = 0; i < sopb->nops; i++) { grpc_stream_op* op = &sopb->ops[i]; if (op->type != GRPC_OP_METADATA) continue; for (m = op->data.metadata.list.head; m != NULL; m = m->next) { if (m->md->key == chand->path_str) { gpr_log(GPR_DEBUG, "%s", (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); /* Add method tag here */ } } } } static void client_mutate_op(grpc_call_element* elem, grpc_transport_stream_op* op) { call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; if (op->send_ops) { extract_and_annotate_method_tag(op->send_ops, calld, chand); } } static void client_start_transport_op(grpc_call_element* elem, grpc_transport_stream_op* op) { client_mutate_op(elem, op); grpc_call_next_op(elem, op); } static void server_on_done_recv(void* ptr, int success) { grpc_call_element* elem = ptr; call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; if (success) { extract_and_annotate_method_tag(calld->recv_ops, calld, chand); } calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } static void server_mutate_op(grpc_call_element* elem, grpc_transport_stream_op* op) { call_data* calld = elem->call_data; if (op->recv_ops) { /* substitute our callback for the op callback */ calld->recv_ops = op->recv_ops; calld->on_done_recv = op->on_done_recv; op->on_done_recv = calld->on_done_recv; } } static void server_start_transport_op(grpc_call_element* elem, grpc_transport_stream_op* op) { call_data* calld = elem->call_data; GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); server_mutate_op(elem, op); grpc_call_next_op(elem, op); } static void client_init_call_elem(grpc_call_element* elem, const void* server_transport_data, grpc_transport_stream_op* initial_op) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); d->start_ts = gpr_now(GPR_CLOCK_REALTIME); if (initial_op) client_mutate_op(elem, initial_op); } static void client_destroy_call_elem(grpc_call_element* elem) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */ } static void server_init_call_elem(grpc_call_element* elem, const void* server_transport_data, grpc_transport_stream_op* initial_op) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); d->start_ts = gpr_now(GPR_CLOCK_REALTIME); /* TODO(hongyu): call census_tracing_start_op here. */ grpc_iomgr_closure_init(d->on_done_recv, server_on_done_recv, elem); if (initial_op) server_mutate_op(elem, initial_op); } static void server_destroy_call_elem(grpc_call_element* elem) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */ } static void init_channel_elem(grpc_channel_element* elem, grpc_channel* master, const grpc_channel_args* args, grpc_mdctx* mdctx, int is_first, int is_last) { channel_data* chand = elem->channel_data; GPR_ASSERT(chand != NULL); chand->path_str = grpc_mdstr_from_string(mdctx, ":path", 0); } static void destroy_channel_elem(grpc_channel_element* elem) { channel_data* chand = elem->channel_data; GPR_ASSERT(chand != NULL); if (chand->path_str != NULL) { GRPC_MDSTR_UNREF(chand->path_str); } } const grpc_channel_filter grpc_client_census_filter = { client_start_transport_op, grpc_channel_next_op, sizeof(call_data), client_init_call_elem, client_destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "census-client"}; const grpc_channel_filter grpc_server_census_filter = { server_start_transport_op, grpc_channel_next_op, sizeof(call_data), server_init_call_elem, server_destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "census-server"}; grpc-0.11.1/src/core/census/tracing.c0000644000175000017500000000360212600663151017532 0ustar apollockapollock/* * * 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 /* TODO(aveitch): These are all placeholder implementations. */ int census_trace_mask(const census_context *context) { return CENSUS_TRACE_MASK_NONE; } void census_set_trace_mask(int trace_mask) {} void census_trace_print(census_context *context, gpr_uint32 type, const char *buffer, size_t n) {} grpc-0.11.1/src/core/census/context.c0000644000175000017500000000357312600663151017576 0ustar apollockapollock/* * * 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/census/context.h" #include #include #include /* Placeholder implementation only. */ size_t census_context_serialize(const census_context *context, char *buffer, size_t buf_size) { /* TODO(aveitch): implement serialization */ return 0; } grpc-0.11.1/src/core/compression/0000755000175000017500000000000012600663151016777 5ustar apollockapollockgrpc-0.11.1/src/core/compression/message_compress.c0000644000175000017500000001367512600663151022516 0ustar apollockapollock/* * * 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/compression/message_compress.h" #include #include #include #include #define OUTPUT_BLOCK_SIZE 1024 static int zlib_body(z_stream *zs, gpr_slice_buffer *input, gpr_slice_buffer *output, int (*flate)(z_stream *zs, int flush)) { int r; int flush; size_t i; gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE); zs->avail_out = GPR_SLICE_LENGTH(outbuf); zs->next_out = GPR_SLICE_START_PTR(outbuf); flush = Z_NO_FLUSH; for (i = 0; i < input->count; i++) { if (i == input->count - 1) flush = Z_FINISH; zs->avail_in = GPR_SLICE_LENGTH(input->slices[i]); zs->next_in = GPR_SLICE_START_PTR(input->slices[i]); do { if (zs->avail_out == 0) { gpr_slice_buffer_add_indexed(output, outbuf); outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE); zs->avail_out = GPR_SLICE_LENGTH(outbuf); zs->next_out = GPR_SLICE_START_PTR(outbuf); } r = flate(zs, flush); if (r == Z_STREAM_ERROR) { gpr_log(GPR_INFO, "zlib: stream error"); goto error; } } while (zs->avail_out == 0); if (zs->avail_in) { gpr_log(GPR_INFO, "zlib: not all input consumed"); goto error; } } GPR_ASSERT(outbuf.refcount); outbuf.data.refcounted.length -= zs->avail_out; gpr_slice_buffer_add_indexed(output, outbuf); return 1; error: gpr_slice_unref(outbuf); return 0; } static int zlib_compress(gpr_slice_buffer *input, gpr_slice_buffer *output, int gzip) { z_stream zs; int r; size_t i; size_t count_before = output->count; size_t length_before = output->length; memset(&zs, 0, sizeof(zs)); r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0), 8, Z_DEFAULT_STRATEGY); if (r != Z_OK) { gpr_log(GPR_ERROR, "deflateInit2 returns %d", r); return 0; } r = zlib_body(&zs, input, output, deflate) && output->length < input->length; if (!r) { for (i = count_before; i < output->count; i++) { gpr_slice_unref(output->slices[i]); } output->count = count_before; output->length = length_before; } deflateEnd(&zs); return r; } static int zlib_decompress(gpr_slice_buffer *input, gpr_slice_buffer *output, int gzip) { z_stream zs; int r; size_t i; size_t count_before = output->count; size_t length_before = output->length; memset(&zs, 0, sizeof(zs)); r = inflateInit2(&zs, 15 | (gzip ? 16 : 0)); if (r != Z_OK) { gpr_log(GPR_ERROR, "inflateInit2 returns %d", r); return 0; } r = zlib_body(&zs, input, output, inflate); if (!r) { for (i = count_before; i < output->count; i++) { gpr_slice_unref(output->slices[i]); } output->count = count_before; output->length = length_before; } inflateEnd(&zs); return r; } static int copy(gpr_slice_buffer *input, gpr_slice_buffer *output) { size_t i; for (i = 0; i < input->count; i++) { gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i])); } return 1; } int compress_inner(grpc_compression_algorithm algorithm, gpr_slice_buffer *input, gpr_slice_buffer *output) { switch (algorithm) { case GRPC_COMPRESS_NONE: /* the fallback path always needs to be send uncompressed: we simply rely on that here */ return 0; case GRPC_COMPRESS_DEFLATE: return zlib_compress(input, output, 0); case GRPC_COMPRESS_GZIP: return zlib_compress(input, output, 1); case GRPC_COMPRESS_ALGORITHMS_COUNT: break; } gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); return 0; } int grpc_msg_compress(grpc_compression_algorithm algorithm, gpr_slice_buffer *input, gpr_slice_buffer *output) { if (!compress_inner(algorithm, input, output)) { copy(input, output); return 0; } return 1; } int grpc_msg_decompress(grpc_compression_algorithm algorithm, gpr_slice_buffer *input, gpr_slice_buffer *output) { switch (algorithm) { case GRPC_COMPRESS_NONE: return copy(input, output); case GRPC_COMPRESS_DEFLATE: return zlib_decompress(input, output, 0); case GRPC_COMPRESS_GZIP: return zlib_decompress(input, output, 1); case GRPC_COMPRESS_ALGORITHMS_COUNT: break; } gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); return 0; } grpc-0.11.1/src/core/compression/algorithm.c0000644000175000017500000000713212600663151021134 0ustar apollockapollock/* * * 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 #include #include int grpc_compression_algorithm_parse(const char *name, size_t name_length, grpc_compression_algorithm *algorithm) { /* we use strncmp not only because it's safer (even though in this case it * doesn't matter, given that we are comparing against string literals, but * because this way we needn't have "name" nil-terminated (useful for slice * data, for example) */ if (name_length == 0) { return 0; } if (strncmp(name, "identity", name_length) == 0) { *algorithm = GRPC_COMPRESS_NONE; } else if (strncmp(name, "gzip", name_length) == 0) { *algorithm = GRPC_COMPRESS_GZIP; } else if (strncmp(name, "deflate", name_length) == 0) { *algorithm = GRPC_COMPRESS_DEFLATE; } else { return 0; } return 1; } int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, char **name) { switch (algorithm) { case GRPC_COMPRESS_NONE: *name = "identity"; break; case GRPC_COMPRESS_DEFLATE: *name = "deflate"; break; case GRPC_COMPRESS_GZIP: *name = "gzip"; break; default: return 0; } return 1; } /* TODO(dgq): Add the ability to specify parameters to the individual * compression algorithms */ grpc_compression_algorithm grpc_compression_algorithm_for_level( grpc_compression_level level) { switch (level) { case GRPC_COMPRESS_LEVEL_NONE: return GRPC_COMPRESS_NONE; case GRPC_COMPRESS_LEVEL_LOW: case GRPC_COMPRESS_LEVEL_MED: case GRPC_COMPRESS_LEVEL_HIGH: return GRPC_COMPRESS_DEFLATE; default: /* we shouldn't be making it here */ abort(); } } grpc_compression_level grpc_compression_level_for_algorithm( grpc_compression_algorithm algorithm) { grpc_compression_level clevel; for (clevel = GRPC_COMPRESS_LEVEL_NONE; clevel < GRPC_COMPRESS_LEVEL_COUNT; ++clevel) { if (grpc_compression_algorithm_for_level(clevel) == algorithm) { return clevel; } } abort(); } grpc-0.11.1/src/core/compression/message_compress.h0000644000175000017500000000461412600663151022514 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H #define GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H #include #include /* compress 'input' to 'output' using 'algorithm'. On success, appends compressed slices to output and returns 1. On failure, appends uncompressed slices to output and returns 0. */ int grpc_msg_compress(grpc_compression_algorithm algorithm, gpr_slice_buffer *input, gpr_slice_buffer *output); /* decompress 'input' to 'output' using 'algorithm'. On success, appends slices to output and returns 1. On failure, output is unchanged, and returns 0. */ int grpc_msg_decompress(grpc_compression_algorithm algorithm, gpr_slice_buffer *input, gpr_slice_buffer *output); #endif /* GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H */ grpc-0.11.1/src/core/client_config/0000755000175000017500000000000012600663151017241 5ustar apollockapollockgrpc-0.11.1/src/core/client_config/resolver_registry.h0000644000175000017500000000600312600663151023202 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H #include "src/core/client_config/resolver_factory.h" void grpc_resolver_registry_init(const char *default_prefix); void grpc_resolver_registry_shutdown(void); /** Register a resolver type. URI's of \a scheme will be resolved with the given resolver. If \a priority is greater than zero, then the resolver will be eligible to resolve names that are passed in with no scheme. Higher priority resolvers will be tried before lower priority schemes. */ void grpc_register_resolver_type(grpc_resolver_factory *factory); /** Create a resolver given \a target. First tries to parse \a target as a URI. If this succeeds, tries to locate a registered resolver factory based on the URI scheme. If parsing or location fails, prefixes default_prefix from grpc_resolver_registry_init to target, and tries again (if default_prefix was not NULL). If a resolver factory was found, use it to instantiate a resolver and return it. If a resolver factory was not found, return NULL. */ grpc_resolver *grpc_resolver_create( const char *target, grpc_subchannel_factory *subchannel_factory); /** Given a target, return a (freshly allocated with gpr_malloc) string representing the default authority to pass from a client. */ char *grpc_get_default_authority(const char *target); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */ grpc-0.11.1/src/core/client_config/README.md0000644000175000017500000000510112600663151020515 0ustar apollockapollockClient Configuration Support for GRPC ===================================== This library provides high level configuration machinery to construct client channels and load balance between them. Each grpc_channel is created with a grpc_resolver. It is the resolver's duty to resolve a name into configuration data for the channel. Such configuration data might include: - a list of (ip, port) addresses to connect to - a load balancing policy to decide which server to send a request to - a set of filters to mutate outgoing requests (say, by adding metadata) The resolver provides this data as a stream of grpc_client_config objects to the channel. We represent configuration as a stream so that it can be changed by the resolver during execution, by reacting to external events (such as a new configuration file being pushed to some store). Load Balancing -------------- Load balancing configuration is provided by a grpc_lb_policy object, stored as part of grpc_client_config. The primary job of the load balancing policies is to pick a target server given only the initial metadata for a request. It does this by providing a grpc_subchannel object to the owning channel. Sub-Channels ------------ A sub-channel provides a connection to a server for a client channel. It has a connectivity state like a regular channel, and so can be connected or disconnected. This connectivity state can be used to inform load balancing decisions (for example, by avoiding disconnected backends). Configured sub-channels are fully setup to participate in the grpc data plane. Their behavior is specified by a set of grpc channel filters defined at their construction. To customize this behavior, resolvers build grpc_subchannel_factory objects, which use the decorator pattern to customize construction arguments for concrete grpc_subchannel instances. Naming for GRPC =============== Names in GRPC are represented by a URI (as defined in [RFC 3986](https://tools.ietf.org/html/rfc3986)). The following schemes are currently supported: dns:///host:port - dns schemes are currently supported so long as authority is empty (authority based dns resolution is expected in a future release) unix:path - the unix scheme is used to create and connect to unix domain sockets - the authority must be empty, and the path represents the absolute or relative path to the desired socket ipv4:host:port - a pre-resolved ipv4 dotted decimal address/port combination ipv6:[host]:port - a pre-resolved ipv6 address/port combination grpc-0.11.1/src/core/client_config/lb_policies/0000755000175000017500000000000012600663151021525 5ustar apollockapollockgrpc-0.11.1/src/core/client_config/lb_policies/pick_first.c0000644000175000017500000002733412600663151024037 0ustar apollockapollock/* * * 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/client_config/lb_policies/pick_first.h" #include #include #include "src/core/transport/connectivity_state.h" typedef struct pending_pick { struct pending_pick *next; grpc_pollset *pollset; grpc_subchannel **target; grpc_iomgr_closure *on_complete; } pending_pick; typedef struct { /** base policy: must be first */ grpc_lb_policy base; /** all our subchannels */ grpc_subchannel **subchannels; size_t num_subchannels; grpc_iomgr_closure connectivity_changed; /** mutex protecting remaining members */ gpr_mu mu; /** the selected channel TODO(ctiller): this should be atomically set so we don't need to take a mutex in the common case */ grpc_subchannel *selected; /** have we started picking? */ int started_picking; /** are we shut down? */ int shutdown; /** which subchannel are we watching? */ size_t checking_subchannel; /** what is the connectivity of that channel? */ grpc_connectivity_state checking_connectivity; /** list of picks that are waiting on connectivity */ pending_pick *pending_picks; /** our connectivity state tracker */ grpc_connectivity_state_tracker state_tracker; } pick_first_lb_policy; static void del_interested_parties_locked(pick_first_lb_policy *p) { pending_pick *pp; for (pp = p->pending_picks; pp; pp = pp->next) { grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel], pp->pollset); } } static void add_interested_parties_locked(pick_first_lb_policy *p) { pending_pick *pp; for (pp = p->pending_picks; pp; pp = pp->next) { grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel], pp->pollset); } } void pf_destroy(grpc_lb_policy *pol) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; size_t i; del_interested_parties_locked(p); for (i = 0; i < p->num_subchannels; i++) { GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first"); } grpc_connectivity_state_destroy(&p->state_tracker); gpr_free(p->subchannels); gpr_mu_destroy(&p->mu); gpr_free(p); } void pf_shutdown(grpc_lb_policy *pol) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pending_pick *pp; gpr_mu_lock(&p->mu); del_interested_parties_locked(p); p->shutdown = 1; while ((pp = p->pending_picks)) { p->pending_picks = pp->next; *pp->target = NULL; grpc_iomgr_add_delayed_callback(pp->on_complete, 0); gpr_free(pp); } grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); gpr_mu_unlock(&p->mu); } static void start_picking(pick_first_lb_policy *p) { p->started_picking = 1; p->checking_subchannel = 0; p->checking_connectivity = GRPC_CHANNEL_IDLE; GRPC_LB_POLICY_REF(&p->base, "pick_first_connectivity"); grpc_subchannel_notify_on_state_change(p->subchannels[p->checking_subchannel], &p->checking_connectivity, &p->connectivity_changed); } void pf_exit_idle(grpc_lb_policy *pol) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; gpr_mu_lock(&p->mu); if (!p->started_picking) { start_picking(p); } gpr_mu_unlock(&p->mu); } void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, grpc_subchannel **target, grpc_iomgr_closure *on_complete) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pending_pick *pp; gpr_mu_lock(&p->mu); if (p->selected) { gpr_mu_unlock(&p->mu); *target = p->selected; on_complete->cb(on_complete->cb_arg, 1); } else { if (!p->started_picking) { start_picking(p); } grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel], pollset); pp = gpr_malloc(sizeof(*pp)); pp->next = p->pending_picks; pp->pollset = pollset; pp->target = target; pp->on_complete = on_complete; p->pending_picks = pp; gpr_mu_unlock(&p->mu); } } static void pf_connectivity_changed(void *arg, int iomgr_success) { pick_first_lb_policy *p = arg; pending_pick *pp; int unref = 0; gpr_mu_lock(&p->mu); if (p->shutdown) { unref = 1; } else if (p->selected != NULL) { grpc_connectivity_state_set(&p->state_tracker, p->checking_connectivity, "selected_changed"); if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) { grpc_subchannel_notify_on_state_change( p->selected, &p->checking_connectivity, &p->connectivity_changed); } else { unref = 1; } } else { loop: switch (p->checking_connectivity) { case GRPC_CHANNEL_READY: grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY, "connecting_ready"); p->selected = p->subchannels[p->checking_subchannel]; while ((pp = p->pending_picks)) { p->pending_picks = pp->next; *pp->target = p->selected; grpc_subchannel_del_interested_party(p->selected, pp->pollset); grpc_iomgr_add_delayed_callback(pp->on_complete, 1); gpr_free(pp); } grpc_subchannel_notify_on_state_change( p->selected, &p->checking_connectivity, &p->connectivity_changed); break; case GRPC_CHANNEL_TRANSIENT_FAILURE: grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, "connecting_transient_failure"); del_interested_parties_locked(p); p->checking_subchannel = (p->checking_subchannel + 1) % p->num_subchannels; p->checking_connectivity = grpc_subchannel_check_connectivity( p->subchannels[p->checking_subchannel]); add_interested_parties_locked(p); if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { grpc_subchannel_notify_on_state_change( p->subchannels[p->checking_subchannel], &p->checking_connectivity, &p->connectivity_changed); } else { goto loop; } break; case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_IDLE: grpc_connectivity_state_set(&p->state_tracker, p->checking_connectivity, "connecting_changed"); grpc_subchannel_notify_on_state_change( p->subchannels[p->checking_subchannel], &p->checking_connectivity, &p->connectivity_changed); break; case GRPC_CHANNEL_FATAL_FAILURE: del_interested_parties_locked(p); GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], p->subchannels[p->num_subchannels - 1]); p->num_subchannels--; GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first"); if (p->num_subchannels == 0) { grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_FATAL_FAILURE, "no_more_channels"); while ((pp = p->pending_picks)) { p->pending_picks = pp->next; *pp->target = NULL; grpc_iomgr_add_delayed_callback(pp->on_complete, 1); gpr_free(pp); } unref = 1; } else { grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, "subchannel_failed"); p->checking_subchannel %= p->num_subchannels; p->checking_connectivity = grpc_subchannel_check_connectivity( p->subchannels[p->checking_subchannel]); add_interested_parties_locked(p); goto loop; } } } gpr_mu_unlock(&p->mu); if (unref) { GRPC_LB_POLICY_UNREF(&p->base, "pick_first_connectivity"); } } static void pf_broadcast(grpc_lb_policy *pol, grpc_transport_op *op) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; size_t i; size_t n; grpc_subchannel **subchannels; gpr_mu_lock(&p->mu); n = p->num_subchannels; subchannels = gpr_malloc(n * sizeof(*subchannels)); for (i = 0; i < n; i++) { subchannels[i] = p->subchannels[i]; GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast"); } gpr_mu_unlock(&p->mu); for (i = 0; i < n; i++) { grpc_subchannel_process_transport_op(subchannels[i], op); GRPC_SUBCHANNEL_UNREF(subchannels[i], "pf_broadcast"); } gpr_free(subchannels); } static grpc_connectivity_state pf_check_connectivity(grpc_lb_policy *pol) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; grpc_connectivity_state st; gpr_mu_lock(&p->mu); st = grpc_connectivity_state_check(&p->state_tracker); gpr_mu_unlock(&p->mu); return st; } static void pf_notify_on_state_change(grpc_lb_policy *pol, grpc_connectivity_state *current, grpc_iomgr_closure *notify) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; gpr_mu_lock(&p->mu); grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current, notify); gpr_mu_unlock(&p->mu); } static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { pf_destroy, pf_shutdown, pf_pick, pf_exit_idle, pf_broadcast, pf_check_connectivity, pf_notify_on_state_change}; grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels, size_t num_subchannels) { pick_first_lb_policy *p = gpr_malloc(sizeof(*p)); GPR_ASSERT(num_subchannels); memset(p, 0, sizeof(*p)); grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable); p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_subchannels); p->num_subchannels = num_subchannels; grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, "pick_first"); memcpy(p->subchannels, subchannels, sizeof(grpc_subchannel *) * num_subchannels); grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p); gpr_mu_init(&p->mu); return &p->base; } grpc-0.11.1/src/core/client_config/lb_policies/pick_first.h0000644000175000017500000000374212600663151024041 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H #include "src/core/client_config/lb_policy.h" /** Returns a load balancing policy instance that picks up the first subchannel * from \a subchannels to succesfully connect */ grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels, size_t num_subchannels); #endif grpc-0.11.1/src/core/client_config/resolver.h0000644000175000017500000001010512600663151021250 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H #include "src/core/client_config/client_config.h" #include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/sockaddr.h" typedef struct grpc_resolver grpc_resolver; typedef struct grpc_resolver_vtable grpc_resolver_vtable; /** grpc_resolver provides grpc_client_config objects to grpc_channel objects */ struct grpc_resolver { const grpc_resolver_vtable *vtable; gpr_refcount refs; }; struct grpc_resolver_vtable { void (*destroy)(grpc_resolver *resolver); void (*shutdown)(grpc_resolver *resolver); void (*channel_saw_error)(grpc_resolver *resolver, struct sockaddr *failing_address, int failing_address_len); void (*next)(grpc_resolver *resolver, grpc_client_config **target_config, grpc_iomgr_closure *on_complete); }; #ifdef GRPC_RESOLVER_REFCOUNT_DEBUG #define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r)) #define GRPC_RESOLVER_UNREF(p, r) \ grpc_resolver_unref((p), __FILE__, __LINE__, (r)) void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line, const char *reason); void grpc_resolver_unref(grpc_resolver *policy, const char *file, int line, const char *reason); #else #define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p)) #define GRPC_RESOLVER_UNREF(p, r) grpc_resolver_unref((p)) void grpc_resolver_ref(grpc_resolver *policy); void grpc_resolver_unref(grpc_resolver *policy); #endif void grpc_resolver_init(grpc_resolver *resolver, const grpc_resolver_vtable *vtable); void grpc_resolver_shutdown(grpc_resolver *resolver); /** Notification that the channel has seen an error on some address. Can be used as a hint that re-resolution is desirable soon. */ void grpc_resolver_channel_saw_error(grpc_resolver *resolver, struct sockaddr *failing_address, int failing_address_len); /** Get the next client config. Called by the channel to fetch a new configuration. Expected to set *target_config with a new configuration, and then schedule on_complete for execution. If resolution is fatally broken, set *target_config to NULL and schedule on_complete. */ void grpc_resolver_next(grpc_resolver *resolver, grpc_client_config **target_config, grpc_iomgr_closure *on_complete); #endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_H */ grpc-0.11.1/src/core/client_config/subchannel_factory.c0000644000175000017500000000375512600663151023270 0ustar apollockapollock/* * * 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/client_config/subchannel_factory.h" void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory) { factory->vtable->ref(factory); } void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory) { factory->vtable->unref(factory); } grpc_subchannel *grpc_subchannel_factory_create_subchannel( grpc_subchannel_factory *factory, grpc_subchannel_args *args) { return factory->vtable->create_subchannel(factory, args); } grpc-0.11.1/src/core/client_config/resolvers/0000755000175000017500000000000012600663151021265 5ustar apollockapollockgrpc-0.11.1/src/core/client_config/resolvers/zookeeper_resolver.c0000644000175000017500000004131712600663151025363 0ustar apollockapollock/* * * 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/client_config/resolvers/zookeeper_resolver.h" #include #include #include #include #include #include "src/core/client_config/lb_policies/pick_first.h" #include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/support/string.h" #include "src/core/json/json.h" /** Zookeeper session expiration time in milliseconds */ #define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000 typedef struct { /** base class: must be first */ grpc_resolver base; /** refcount */ gpr_refcount refs; /** name to resolve */ char *name; /** subchannel factory */ grpc_subchannel_factory *subchannel_factory; /** load balancing policy factory */ grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, size_t num_subchannels); /** mutex guarding the rest of the state */ gpr_mu mu; /** are we currently resolving? */ int resolving; /** which version of resolved_config have we published? */ int published_version; /** which version of resolved_config is current? */ int resolved_version; /** pending next completion, or NULL */ grpc_iomgr_closure *next_completion; /** target config address for next completion */ grpc_client_config **target_config; /** current (fully resolved) config */ grpc_client_config *resolved_config; /** zookeeper handle */ zhandle_t *zookeeper_handle; /** zookeeper resolved addresses */ grpc_resolved_addresses *resolved_addrs; /** total number of addresses to be resolved */ int resolved_total; /** number of addresses resolved */ int resolved_num; } zookeeper_resolver; static void zookeeper_destroy(grpc_resolver *r); static void zookeeper_start_resolving_locked(zookeeper_resolver *r); static void zookeeper_maybe_finish_next_locked(zookeeper_resolver *r); static void zookeeper_shutdown(grpc_resolver *r); static void zookeeper_channel_saw_error(grpc_resolver *r, struct sockaddr *failing_address, int failing_address_len); static void zookeeper_next(grpc_resolver *r, grpc_client_config **target_config, grpc_iomgr_closure *on_complete); static const grpc_resolver_vtable zookeeper_resolver_vtable = { zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error, zookeeper_next}; static void zookeeper_shutdown(grpc_resolver *resolver) { zookeeper_resolver *r = (zookeeper_resolver *)resolver; gpr_mu_lock(&r->mu); if (r->next_completion != NULL) { *r->target_config = NULL; grpc_iomgr_add_callback(r->next_completion); r->next_completion = NULL; } zookeeper_close(r->zookeeper_handle); gpr_mu_unlock(&r->mu); } static void zookeeper_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa, int len) { zookeeper_resolver *r = (zookeeper_resolver *)resolver; gpr_mu_lock(&r->mu); if (r->resolving == 0) { zookeeper_start_resolving_locked(r); } gpr_mu_unlock(&r->mu); } static void zookeeper_next(grpc_resolver *resolver, grpc_client_config **target_config, grpc_iomgr_closure *on_complete) { zookeeper_resolver *r = (zookeeper_resolver *)resolver; gpr_mu_lock(&r->mu); GPR_ASSERT(r->next_completion == NULL); r->next_completion = on_complete; r->target_config = target_config; if (r->resolved_version == 0 && r->resolving == 0) { zookeeper_start_resolving_locked(r); } else { zookeeper_maybe_finish_next_locked(r); } gpr_mu_unlock(&r->mu); } /** Zookeeper global watcher for connection management TODO: better connection management besides logs */ static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type, int state, const char *path, void *watcher_ctx) { if (type == ZOO_SESSION_EVENT) { if (state == ZOO_EXPIRED_SESSION_STATE) { gpr_log(GPR_ERROR, "Zookeeper session expired"); } else if (state == ZOO_AUTH_FAILED_STATE) { gpr_log(GPR_ERROR, "Zookeeper authentication failed"); } } } /** Zookeeper watcher triggered by changes to watched nodes Once triggered, it tries to resolve again to get updated addresses */ static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state, const char *path, void *watcher_ctx) { if (watcher_ctx != NULL) { zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx; if (state == ZOO_CONNECTED_STATE) { gpr_mu_lock(&r->mu); if (r->resolving == 0) { zookeeper_start_resolving_locked(r); } gpr_mu_unlock(&r->mu); } } } /** Callback function after getting all resolved addresses Creates a subchannel for each address */ static void zookeeper_on_resolved(void *arg, grpc_resolved_addresses *addresses) { zookeeper_resolver *r = arg; grpc_client_config *config = NULL; grpc_subchannel **subchannels; grpc_subchannel_args args; grpc_lb_policy *lb_policy; size_t i; if (addresses != NULL) { config = grpc_client_config_create(); subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); for (i = 0; i < addresses->naddrs; i++) { memset(&args, 0, sizeof(args)); args.addr = (struct sockaddr *)(addresses->addrs[i].addr); args.addr_len = addresses->addrs[i].len; subchannels[i] = grpc_subchannel_factory_create_subchannel( r->subchannel_factory, &args); } lb_policy = r->lb_policy_factory(subchannels, addresses->naddrs); grpc_client_config_set_lb_policy(config, lb_policy); GRPC_LB_POLICY_UNREF(lb_policy, "construction"); grpc_resolved_addresses_destroy(addresses); gpr_free(subchannels); } gpr_mu_lock(&r->mu); GPR_ASSERT(r->resolving == 1); r->resolving = 0; if (r->resolved_config != NULL) { grpc_client_config_unref(r->resolved_config); } r->resolved_config = config; r->resolved_version++; zookeeper_maybe_finish_next_locked(r); gpr_mu_unlock(&r->mu); GRPC_RESOLVER_UNREF(&r->base, "zookeeper-resolving"); } /** Callback function for each DNS resolved address */ static void zookeeper_dns_resolved(void *arg, grpc_resolved_addresses *addresses) { size_t i; zookeeper_resolver *r = arg; int resolve_done = 0; gpr_mu_lock(&r->mu); r->resolved_num++; r->resolved_addrs->addrs = gpr_realloc(r->resolved_addrs->addrs, sizeof(grpc_resolved_address) * (r->resolved_addrs->naddrs + addresses->naddrs)); for (i = 0; i < addresses->naddrs; i++) { memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr, addresses->addrs[i].addr, addresses->addrs[i].len); r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len = addresses->addrs[i].len; } r->resolved_addrs->naddrs += addresses->naddrs; grpc_resolved_addresses_destroy(addresses); /** Wait for all addresses to be resolved */ resolve_done = (r->resolved_num == r->resolved_total); gpr_mu_unlock(&r->mu); if (resolve_done) { zookeeper_on_resolved(r, r->resolved_addrs); } } /** Parses JSON format address of a zookeeper node */ static char *zookeeper_parse_address(const char *value, int value_len) { grpc_json *json; grpc_json *cur; const char *host; const char *port; char *buffer; char *address = NULL; buffer = gpr_malloc(value_len); memcpy(buffer, value, value_len); json = grpc_json_parse_string_with_len(buffer, value_len); if (json != NULL) { host = NULL; port = NULL; for (cur = json->child; cur != NULL; cur = cur->next) { if (!strcmp(cur->key, "host")) { host = cur->value; if (port != NULL) { break; } } else if (!strcmp(cur->key, "port")) { port = cur->value; if (host != NULL) { break; } } } if (host != NULL && port != NULL) { gpr_asprintf(&address, "%s:%s", host, port); } grpc_json_destroy(json); } gpr_free(buffer); return address; } static void zookeeper_get_children_node_completion(int rc, const char *value, int value_len, const struct Stat *stat, const void *arg) { char *address = NULL; zookeeper_resolver *r = (zookeeper_resolver *)arg; int resolve_done = 0; if (rc != 0) { gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name); return; } address = zookeeper_parse_address(value, value_len); if (address != NULL) { /** Further resolves address by DNS */ grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r); gpr_free(address); } else { gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name); gpr_mu_lock(&r->mu); r->resolved_total--; resolve_done = (r->resolved_num == r->resolved_total); gpr_mu_unlock(&r->mu); if (resolve_done) { zookeeper_on_resolved(r, r->resolved_addrs); } } } static void zookeeper_get_children_completion( int rc, const struct String_vector *children, const void *arg) { char *path; int status; int i; zookeeper_resolver *r = (zookeeper_resolver *)arg; if (rc != 0) { gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name); return; } if (children->count == 0) { gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name); return; } r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); r->resolved_addrs->addrs = NULL; r->resolved_addrs->naddrs = 0; r->resolved_total = children->count; /** TODO: Replace expensive heap allocation with stack if we can get maximum length of zookeeper path */ for (i = 0; i < children->count; i++) { gpr_asprintf(&path, "%s/%s", r->name, children->data[i]); status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r, zookeeper_get_children_node_completion, r); gpr_free(path); if (status != 0) { gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path); } } } static void zookeeper_get_node_completion(int rc, const char *value, int value_len, const struct Stat *stat, const void *arg) { int status; char *address = NULL; zookeeper_resolver *r = (zookeeper_resolver *)arg; r->resolved_addrs = NULL; r->resolved_total = 0; r->resolved_num = 0; if (rc != 0) { gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name); return; } /** If zookeeper node of path r->name does not have address (i.e. service node), get its children */ address = zookeeper_parse_address(value, value_len); if (address != NULL) { r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); r->resolved_addrs->addrs = NULL; r->resolved_addrs->naddrs = 0; r->resolved_total = 1; /** Further resolves address by DNS */ grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r); gpr_free(address); return; } status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher, r, zookeeper_get_children_completion, r); if (status != 0) { gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name); } } static void zookeeper_resolve_address(zookeeper_resolver *r) { int status; status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r, zookeeper_get_node_completion, r); if (status != 0) { gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name); } } static void zookeeper_start_resolving_locked(zookeeper_resolver *r) { GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving"); GPR_ASSERT(r->resolving == 0); r->resolving = 1; zookeeper_resolve_address(r); } static void zookeeper_maybe_finish_next_locked(zookeeper_resolver *r) { if (r->next_completion != NULL && r->resolved_version != r->published_version) { *r->target_config = r->resolved_config; if (r->resolved_config != NULL) { grpc_client_config_ref(r->resolved_config); } grpc_iomgr_add_callback(r->next_completion); r->next_completion = NULL; r->published_version = r->resolved_version; } } static void zookeeper_destroy(grpc_resolver *gr) { zookeeper_resolver *r = (zookeeper_resolver *)gr; gpr_mu_destroy(&r->mu); if (r->resolved_config != NULL) { grpc_client_config_unref(r->resolved_config); } grpc_subchannel_factory_unref(r->subchannel_factory); gpr_free(r->name); gpr_free(r); } static grpc_resolver *zookeeper_create( grpc_uri *uri, grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, size_t num_subchannels), grpc_subchannel_factory *subchannel_factory) { zookeeper_resolver *r; size_t length; char *path = uri->path; if (0 == strcmp(uri->authority, "")) { gpr_log(GPR_ERROR, "No authority specified in zookeeper uri"); return NULL; } /** Removes the trailing slash if exists */ length = strlen(path); if (length > 1 && path[length - 1] == '/') { path[length - 1] = 0; } r = gpr_malloc(sizeof(zookeeper_resolver)); memset(r, 0, sizeof(*r)); gpr_ref_init(&r->refs, 1); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &zookeeper_resolver_vtable); r->name = gpr_strdup(path); r->subchannel_factory = subchannel_factory; r->lb_policy_factory = lb_policy_factory; grpc_subchannel_factory_ref(subchannel_factory); /** Initializes zookeeper client */ zoo_set_debug_level(ZOO_LOG_LEVEL_WARN); r->zookeeper_handle = zookeeper_init(uri->authority, zookeeper_global_watcher, GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0); if (r->zookeeper_handle == NULL) { gpr_log(GPR_ERROR, "Unable to connect to zookeeper server"); return NULL; } return &r->base; } static void zookeeper_plugin_init() { grpc_register_resolver_type(grpc_zookeeper_resolver_factory_create()); } void grpc_zookeeper_register() { grpc_register_plugin(zookeeper_plugin_init, NULL); } /* * FACTORY */ static void zookeeper_factory_ref(grpc_resolver_factory *factory) {} static void zookeeper_factory_unref(grpc_resolver_factory *factory) {} static char *zookeeper_factory_get_default_hostname( grpc_resolver_factory *factory, grpc_uri *uri) { return NULL; } static grpc_resolver *zookeeper_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory) { return zookeeper_create(uri, grpc_create_pick_first_lb_policy, subchannel_factory); } static const grpc_resolver_factory_vtable zookeeper_factory_vtable = { zookeeper_factory_ref, zookeeper_factory_unref, zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname, "zookeeper"}; static grpc_resolver_factory zookeeper_resolver_factory = { &zookeeper_factory_vtable}; grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() { return &zookeeper_resolver_factory; } grpc-0.11.1/src/core/client_config/resolvers/sockaddr_resolver.c0000644000175000017500000002663612600663151025161 0ustar apollockapollock/* * * 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 #include "src/core/client_config/resolvers/sockaddr_resolver.h" #include #include #ifdef GPR_POSIX_SOCKET #include #endif #include #include #include #include "src/core/client_config/lb_policies/pick_first.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/support/string.h" typedef struct { /** base class: must be first */ grpc_resolver base; /** refcount */ gpr_refcount refs; /** subchannel factory */ grpc_subchannel_factory *subchannel_factory; /** load balancing policy factory */ grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, size_t num_subchannels); /** the addresses that we've 'resolved' */ struct sockaddr_storage *addrs; /** the corresponding length of the addresses */ int *addrs_len; /** how many elements in \a addrs */ size_t num_addrs; /** mutex guarding the rest of the state */ gpr_mu mu; /** have we published? */ int published; /** pending next completion, or NULL */ grpc_iomgr_closure *next_completion; /** target config address for next completion */ grpc_client_config **target_config; } sockaddr_resolver; static void sockaddr_destroy(grpc_resolver *r); static void sockaddr_maybe_finish_next_locked(sockaddr_resolver *r); static void sockaddr_shutdown(grpc_resolver *r); static void sockaddr_channel_saw_error(grpc_resolver *r, struct sockaddr *failing_address, int failing_address_len); static void sockaddr_next(grpc_resolver *r, grpc_client_config **target_config, grpc_iomgr_closure *on_complete); static const grpc_resolver_vtable sockaddr_resolver_vtable = { sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error, sockaddr_next}; static void sockaddr_shutdown(grpc_resolver *resolver) { sockaddr_resolver *r = (sockaddr_resolver *)resolver; gpr_mu_lock(&r->mu); if (r->next_completion != NULL) { *r->target_config = NULL; /* TODO(ctiller): add delayed callback */ grpc_iomgr_add_callback(r->next_completion); r->next_completion = NULL; } gpr_mu_unlock(&r->mu); } static void sockaddr_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa, int len) {} static void sockaddr_next(grpc_resolver *resolver, grpc_client_config **target_config, grpc_iomgr_closure *on_complete) { sockaddr_resolver *r = (sockaddr_resolver *)resolver; gpr_mu_lock(&r->mu); GPR_ASSERT(!r->next_completion); r->next_completion = on_complete; r->target_config = target_config; sockaddr_maybe_finish_next_locked(r); gpr_mu_unlock(&r->mu); } static void sockaddr_maybe_finish_next_locked(sockaddr_resolver *r) { grpc_client_config *cfg; grpc_lb_policy *lb_policy; grpc_subchannel **subchannels; grpc_subchannel_args args; if (r->next_completion != NULL && !r->published) { size_t i; cfg = grpc_client_config_create(); subchannels = gpr_malloc(sizeof(grpc_subchannel *) * r->num_addrs); for (i = 0; i < r->num_addrs; i++) { memset(&args, 0, sizeof(args)); args.addr = (struct sockaddr *)&r->addrs[i]; args.addr_len = r->addrs_len[i]; subchannels[i] = grpc_subchannel_factory_create_subchannel( r->subchannel_factory, &args); } lb_policy = r->lb_policy_factory(subchannels, r->num_addrs); gpr_free(subchannels); grpc_client_config_set_lb_policy(cfg, lb_policy); GRPC_LB_POLICY_UNREF(lb_policy, "unix"); r->published = 1; *r->target_config = cfg; grpc_iomgr_add_callback(r->next_completion); r->next_completion = NULL; } } static void sockaddr_destroy(grpc_resolver *gr) { sockaddr_resolver *r = (sockaddr_resolver *)gr; gpr_mu_destroy(&r->mu); grpc_subchannel_factory_unref(r->subchannel_factory); gpr_free(r->addrs); gpr_free(r->addrs_len); gpr_free(r); } #ifdef GPR_POSIX_SOCKET static int parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, int *len) { struct sockaddr_un *un = (struct sockaddr_un *)addr; un->sun_family = AF_UNIX; strcpy(un->sun_path, uri->path); *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; return 1; } static char *unix_get_default_authority(grpc_resolver_factory *factory, grpc_uri *uri) { return gpr_strdup("localhost"); } #endif static char *ip_get_default_authority(grpc_uri *uri) { const char *path = uri->path; if (path[0] == '/') ++path; return gpr_strdup(path); } static char *ipv4_get_default_authority(grpc_resolver_factory *factory, grpc_uri *uri) { return ip_get_default_authority(uri); } static char *ipv6_get_default_authority(grpc_resolver_factory *factory, grpc_uri *uri) { return ip_get_default_authority(uri); } static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr, int *len) { const char *host_port = uri->path; char *host; char *port; int port_num; int result = 0; struct sockaddr_in *in = (struct sockaddr_in *)addr; if (*host_port == '/') ++host_port; if (!gpr_split_host_port(host_port, &host, &port)) { return 0; } memset(in, 0, sizeof(*in)); *len = sizeof(*in); in->sin_family = AF_INET; if (inet_pton(AF_INET, host, &in->sin_addr) == 0) { gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host); goto done; } if (port != NULL) { if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) { gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port); goto done; } in->sin_port = htons(port_num); } else { gpr_log(GPR_ERROR, "no port given for ipv4 scheme"); goto done; } result = 1; done: gpr_free(host); gpr_free(port); return result; } static int parse_ipv6(grpc_uri *uri, struct sockaddr_storage *addr, int *len) { const char *host_port = uri->path; char *host; char *port; int port_num; int result = 0; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; if (*host_port == '/') ++host_port; if (!gpr_split_host_port(host_port, &host, &port)) { return 0; } memset(in6, 0, sizeof(*in6)); *len = sizeof(*in6); in6->sin6_family = AF_INET6; if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) { gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); goto done; } if (port != NULL) { if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) { gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port); goto done; } in6->sin6_port = htons(port_num); } else { gpr_log(GPR_ERROR, "no port given for ipv6 scheme"); goto done; } result = 1; done: gpr_free(host); gpr_free(port); return result; } static void do_nothing(void *ignored) {} static grpc_resolver *sockaddr_create( grpc_uri *uri, grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, size_t num_subchannels), grpc_subchannel_factory *subchannel_factory, int parse(grpc_uri *uri, struct sockaddr_storage *dst, int *len)) { size_t i; int errors_found = 0; /* GPR_FALSE */ sockaddr_resolver *r; gpr_slice path_slice; gpr_slice_buffer path_parts; if (0 != strcmp(uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported"); return NULL; } r = gpr_malloc(sizeof(sockaddr_resolver)); memset(r, 0, sizeof(*r)); path_slice = gpr_slice_new(uri->path, strlen(uri->path), do_nothing); gpr_slice_buffer_init(&path_parts); gpr_slice_split(path_slice, ",", &path_parts); r->num_addrs = path_parts.count; r->addrs = gpr_malloc(sizeof(struct sockaddr_storage) * r->num_addrs); r->addrs_len = gpr_malloc(sizeof(int) * r->num_addrs); for(i = 0; i < r->num_addrs; i++) { grpc_uri ith_uri = *uri; char* part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); ith_uri.path = part_str; if (!parse(&ith_uri, &r->addrs[i], &r->addrs_len[i])) { errors_found = 1; /* GPR_TRUE */ } gpr_free(part_str); if (errors_found) break; } gpr_slice_buffer_destroy(&path_parts); gpr_slice_unref(path_slice); if (errors_found) { gpr_free(r); return NULL; } gpr_ref_init(&r->refs, 1); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); r->subchannel_factory = subchannel_factory; r->lb_policy_factory = lb_policy_factory; grpc_subchannel_factory_ref(subchannel_factory); return &r->base; } /* * FACTORY */ static void sockaddr_factory_ref(grpc_resolver_factory *factory) {} static void sockaddr_factory_unref(grpc_resolver_factory *factory) {} #define DECL_FACTORY(name) \ static grpc_resolver *name##_factory_create_resolver( \ grpc_resolver_factory *factory, grpc_uri *uri, \ grpc_subchannel_factory *subchannel_factory) { \ return sockaddr_create(uri, grpc_create_pick_first_lb_policy, \ subchannel_factory, parse_##name); \ } \ static const grpc_resolver_factory_vtable name##_factory_vtable = { \ sockaddr_factory_ref, sockaddr_factory_unref, \ name##_factory_create_resolver, name##_get_default_authority, #name}; \ static grpc_resolver_factory name##_resolver_factory = { \ &name##_factory_vtable}; \ grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \ return &name##_resolver_factory; \ } #ifdef GPR_POSIX_SOCKET DECL_FACTORY(unix) #endif DECL_FACTORY(ipv4) DECL_FACTORY(ipv6) grpc-0.11.1/src/core/client_config/resolvers/zookeeper_resolver.h0000644000175000017500000000364712600663151025374 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H #include "src/core/client_config/resolver_factory.h" /** Create a zookeeper resolver factory */ grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */ grpc-0.11.1/src/core/client_config/resolvers/sockaddr_resolver.h0000644000175000017500000000413012600663151025147 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H #include #include "src/core/client_config/resolver_factory.h" grpc_resolver_factory *grpc_ipv4_resolver_factory_create(void); grpc_resolver_factory *grpc_ipv6_resolver_factory_create(void); #ifdef GPR_POSIX_SOCKET /** Create a unix resolver factory */ grpc_resolver_factory *grpc_unix_resolver_factory_create(void); #endif #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H */ grpc-0.11.1/src/core/client_config/resolvers/dns_resolver.h0000644000175000017500000000361112600663151024144 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H #include "src/core/client_config/resolver_factory.h" /** Create a dns resolver factory */ grpc_resolver_factory *grpc_dns_resolver_factory_create(void); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */ grpc-0.11.1/src/core/client_config/resolvers/dns_resolver.c0000644000175000017500000002114712600663151024143 0ustar apollockapollock/* * * 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/client_config/resolvers/dns_resolver.h" #include #include #include #include #include "src/core/client_config/lb_policies/pick_first.h" #include "src/core/client_config/subchannel_factory_decorators/add_channel_arg.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/support/string.h" typedef struct { /** base class: must be first */ grpc_resolver base; /** refcount */ gpr_refcount refs; /** name to resolve */ char *name; /** default port to use */ char *default_port; /** subchannel factory */ grpc_subchannel_factory *subchannel_factory; /** load balancing policy factory */ grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, size_t num_subchannels); /** mutex guarding the rest of the state */ gpr_mu mu; /** are we currently resolving? */ int resolving; /** which version of resolved_config have we published? */ int published_version; /** which version of resolved_config is current? */ int resolved_version; /** pending next completion, or NULL */ grpc_iomgr_closure *next_completion; /** target config address for next completion */ grpc_client_config **target_config; /** current (fully resolved) config */ grpc_client_config *resolved_config; } dns_resolver; static void dns_destroy(grpc_resolver *r); static void dns_start_resolving_locked(dns_resolver *r); static void dns_maybe_finish_next_locked(dns_resolver *r); static void dns_shutdown(grpc_resolver *r); static void dns_channel_saw_error(grpc_resolver *r, struct sockaddr *failing_address, int failing_address_len); static void dns_next(grpc_resolver *r, grpc_client_config **target_config, grpc_iomgr_closure *on_complete); static const grpc_resolver_vtable dns_resolver_vtable = { dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next}; static void dns_shutdown(grpc_resolver *resolver) { dns_resolver *r = (dns_resolver *)resolver; gpr_mu_lock(&r->mu); if (r->next_completion != NULL) { *r->target_config = NULL; grpc_iomgr_add_callback(r->next_completion); r->next_completion = NULL; } gpr_mu_unlock(&r->mu); } static void dns_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa, int len) { dns_resolver *r = (dns_resolver *)resolver; gpr_mu_lock(&r->mu); if (!r->resolving) { dns_start_resolving_locked(r); } gpr_mu_unlock(&r->mu); } static void dns_next(grpc_resolver *resolver, grpc_client_config **target_config, grpc_iomgr_closure *on_complete) { dns_resolver *r = (dns_resolver *)resolver; gpr_mu_lock(&r->mu); GPR_ASSERT(!r->next_completion); r->next_completion = on_complete; r->target_config = target_config; if (r->resolved_version == 0 && !r->resolving) { dns_start_resolving_locked(r); } else { dns_maybe_finish_next_locked(r); } gpr_mu_unlock(&r->mu); } static void dns_on_resolved(void *arg, grpc_resolved_addresses *addresses) { dns_resolver *r = arg; grpc_client_config *config = NULL; grpc_subchannel **subchannels; grpc_subchannel_args args; grpc_lb_policy *lb_policy; size_t i; if (addresses) { config = grpc_client_config_create(); subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); for (i = 0; i < addresses->naddrs; i++) { memset(&args, 0, sizeof(args)); args.addr = (struct sockaddr *)(addresses->addrs[i].addr); args.addr_len = addresses->addrs[i].len; subchannels[i] = grpc_subchannel_factory_create_subchannel( r->subchannel_factory, &args); } lb_policy = r->lb_policy_factory(subchannels, addresses->naddrs); grpc_client_config_set_lb_policy(config, lb_policy); GRPC_LB_POLICY_UNREF(lb_policy, "construction"); grpc_resolved_addresses_destroy(addresses); gpr_free(subchannels); } gpr_mu_lock(&r->mu); GPR_ASSERT(r->resolving); r->resolving = 0; if (r->resolved_config) { grpc_client_config_unref(r->resolved_config); } r->resolved_config = config; r->resolved_version++; dns_maybe_finish_next_locked(r); gpr_mu_unlock(&r->mu); GRPC_RESOLVER_UNREF(&r->base, "dns-resolving"); } static void dns_start_resolving_locked(dns_resolver *r) { GRPC_RESOLVER_REF(&r->base, "dns-resolving"); GPR_ASSERT(!r->resolving); r->resolving = 1; grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r); } static void dns_maybe_finish_next_locked(dns_resolver *r) { if (r->next_completion != NULL && r->resolved_version != r->published_version) { *r->target_config = r->resolved_config; if (r->resolved_config) { grpc_client_config_ref(r->resolved_config); } grpc_iomgr_add_callback(r->next_completion); r->next_completion = NULL; r->published_version = r->resolved_version; } } static void dns_destroy(grpc_resolver *gr) { dns_resolver *r = (dns_resolver *)gr; gpr_mu_destroy(&r->mu); if (r->resolved_config) { grpc_client_config_unref(r->resolved_config); } grpc_subchannel_factory_unref(r->subchannel_factory); gpr_free(r->name); gpr_free(r->default_port); gpr_free(r); } static grpc_resolver *dns_create( grpc_uri *uri, const char *default_port, grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels, size_t num_subchannels), grpc_subchannel_factory *subchannel_factory) { dns_resolver *r; const char *path = uri->path; if (0 != strcmp(uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported"); return NULL; } if (path[0] == '/') ++path; r = gpr_malloc(sizeof(dns_resolver)); memset(r, 0, sizeof(*r)); gpr_ref_init(&r->refs, 1); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &dns_resolver_vtable); r->name = gpr_strdup(path); r->default_port = gpr_strdup(default_port); r->subchannel_factory = subchannel_factory; grpc_subchannel_factory_ref(subchannel_factory); r->lb_policy_factory = lb_policy_factory; return &r->base; } /* * FACTORY */ static void dns_factory_ref(grpc_resolver_factory *factory) {} static void dns_factory_unref(grpc_resolver_factory *factory) {} static grpc_resolver *dns_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory) { return dns_create(uri, "https", grpc_create_pick_first_lb_policy, subchannel_factory); } char *dns_factory_get_default_host_name(grpc_resolver_factory *factory, grpc_uri *uri) { const char *path = uri->path; if (path[0] == '/') ++path; return gpr_strdup(path); } static const grpc_resolver_factory_vtable dns_factory_vtable = { dns_factory_ref, dns_factory_unref, dns_factory_create_resolver, dns_factory_get_default_host_name, "dns"}; static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable}; grpc_resolver_factory *grpc_dns_resolver_factory_create() { return &dns_resolver_factory; } grpc-0.11.1/src/core/client_config/subchannel.h0000644000175000017500000001310012600663151021527 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H #include "src/core/channel/channel_stack.h" #include "src/core/client_config/connector.h" /** A (sub-)channel that knows how to connect to exactly one target address. Provides a target for load balancing. */ typedef struct grpc_subchannel grpc_subchannel; typedef struct grpc_subchannel_call grpc_subchannel_call; typedef struct grpc_subchannel_args grpc_subchannel_args; #ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG #define GRPC_SUBCHANNEL_REF(p, r) \ grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_UNREF(p, r) \ grpc_subchannel_unref((p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_CALL_REF(p, r) \ grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_CALL_UNREF(p, r) \ grpc_subchannel_call_unref((p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \ , const char *file, int line, const char *reason #else #define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p)) #define GRPC_SUBCHANNEL_UNREF(p, r) grpc_subchannel_unref((p)) #define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p)) #define GRPC_SUBCHANNEL_CALL_UNREF(p, r) grpc_subchannel_call_unref((p)) #define GRPC_SUBCHANNEL_REF_EXTRA_ARGS #endif void grpc_subchannel_ref( grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); void grpc_subchannel_unref( grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); void grpc_subchannel_call_ref( grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS); void grpc_subchannel_call_unref( grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS); /** construct a call (possibly asynchronously) */ void grpc_subchannel_create_call(grpc_subchannel *subchannel, grpc_pollset *pollset, grpc_subchannel_call **target, grpc_iomgr_closure *notify); /** process a transport level op */ void grpc_subchannel_process_transport_op(grpc_subchannel *subchannel, grpc_transport_op *op); /** poll the current connectivity state of a channel */ grpc_connectivity_state grpc_subchannel_check_connectivity( grpc_subchannel *channel); /** call notify when the connectivity state of a channel changes from *state. Updates *state with the new state of the channel */ void grpc_subchannel_notify_on_state_change(grpc_subchannel *channel, grpc_connectivity_state *state, grpc_iomgr_closure *notify); /** express interest in \a channel's activities through \a pollset. */ void grpc_subchannel_add_interested_party(grpc_subchannel *channel, grpc_pollset *pollset); /** stop following \a channel's activity through \a pollset. */ void grpc_subchannel_del_interested_party(grpc_subchannel *channel, grpc_pollset *pollset); /** continue processing a transport op */ void grpc_subchannel_call_process_op(grpc_subchannel_call *subchannel_call, grpc_transport_stream_op *op); /** continue querying for peer */ char *grpc_subchannel_call_get_peer(grpc_subchannel_call *subchannel_call); struct grpc_subchannel_args { /** Channel filters for this channel - wrapped factories will likely want to mutate this */ const grpc_channel_filter **filters; /** The number of filters in the above array */ size_t filter_count; /** Channel arguments to be supplied to the newly created channel */ const grpc_channel_args *args; /** Address to connect to */ struct sockaddr *addr; size_t addr_len; /** metadata context to use */ grpc_mdctx *mdctx; /** master channel */ grpc_channel *master; }; /** create a subchannel given a connector */ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, grpc_subchannel_args *args); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */ grpc-0.11.1/src/core/client_config/connector.h0000644000175000017500000000632612600663151021413 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H #include "src/core/channel/channel_stack.h" #include "src/core/iomgr/sockaddr.h" #include "src/core/transport/transport.h" typedef struct grpc_connector grpc_connector; typedef struct grpc_connector_vtable grpc_connector_vtable; struct grpc_connector { const grpc_connector_vtable *vtable; }; typedef struct { /** set of pollsets interested in this connection */ grpc_pollset_set *interested_parties; /** address to connect to */ const struct sockaddr *addr; int addr_len; /** deadline for connection */ gpr_timespec deadline; /** channel arguments (to be passed to transport) */ const grpc_channel_args *channel_args; /** metadata context */ grpc_mdctx *metadata_context; } grpc_connect_in_args; typedef struct { /** the connected transport */ grpc_transport *transport; /** any additional filters (owned by the caller of connect) */ const grpc_channel_filter **filters; size_t num_filters; } grpc_connect_out_args; struct grpc_connector_vtable { void (*ref)(grpc_connector *connector); void (*unref)(grpc_connector *connector); void (*connect)(grpc_connector *connector, const grpc_connect_in_args *in_args, grpc_connect_out_args *out_args, grpc_iomgr_closure *notify); }; void grpc_connector_ref(grpc_connector *connector); void grpc_connector_unref(grpc_connector *connector); void grpc_connector_connect(grpc_connector *connector, const grpc_connect_in_args *in_args, grpc_connect_out_args *out_args, grpc_iomgr_closure *notify); #endif grpc-0.11.1/src/core/client_config/resolver_factory.c0000644000175000017500000000446012600663151023001 0ustar apollockapollock/* * * 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/client_config/resolver_factory.h" void grpc_resolver_factory_ref(grpc_resolver_factory *factory) { factory->vtable->ref(factory); } void grpc_resolver_factory_unref(grpc_resolver_factory *factory) { factory->vtable->unref(factory); } /** Create a resolver instance for a name */ grpc_resolver *grpc_resolver_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory) { if (factory == NULL) return NULL; return factory->vtable->create_resolver(factory, uri, subchannel_factory); } char *grpc_resolver_factory_get_default_authority( grpc_resolver_factory *factory, grpc_uri *uri) { if (factory == NULL) return NULL; return factory->vtable->get_default_authority(factory, uri); } grpc-0.11.1/src/core/client_config/lb_policy.h0000644000175000017500000001212212600663151021364 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H #include "src/core/client_config/subchannel.h" /** A load balancing policy: specified by a vtable and a struct (which is expected to be extended to contain some parameters) */ typedef struct grpc_lb_policy grpc_lb_policy; typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable; typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel, grpc_status_code status, const char *errmsg); struct grpc_lb_policy { const grpc_lb_policy_vtable *vtable; gpr_refcount refs; }; struct grpc_lb_policy_vtable { void (*destroy)(grpc_lb_policy *policy); void (*shutdown)(grpc_lb_policy *policy); /** implement grpc_lb_policy_pick */ void (*pick)(grpc_lb_policy *policy, grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, grpc_subchannel **target, grpc_iomgr_closure *on_complete); /** try to enter a READY connectivity state */ void (*exit_idle)(grpc_lb_policy *policy); /** broadcast a transport op to all subchannels */ void (*broadcast)(grpc_lb_policy *policy, grpc_transport_op *op); /** check the current connectivity of the lb_policy */ grpc_connectivity_state (*check_connectivity)(grpc_lb_policy *policy); /** call notify when the connectivity state of a channel changes from *state. Updates *state with the new state of the policy */ void (*notify_on_state_change)(grpc_lb_policy *policy, grpc_connectivity_state *state, grpc_iomgr_closure *closure); }; #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG #define GRPC_LB_POLICY_REF(p, r) \ grpc_lb_policy_ref((p), __FILE__, __LINE__, (r)) #define GRPC_LB_POLICY_UNREF(p, r) \ grpc_lb_policy_unref((p), __FILE__, __LINE__, (r)) void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, const char *reason); void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line, const char *reason); #else #define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p)) #define GRPC_LB_POLICY_UNREF(p, r) grpc_lb_policy_unref((p)) void grpc_lb_policy_ref(grpc_lb_policy *policy); void grpc_lb_policy_unref(grpc_lb_policy *policy); #endif /** called by concrete implementations to initialize the base struct */ void grpc_lb_policy_init(grpc_lb_policy *policy, const grpc_lb_policy_vtable *vtable); /** Start shutting down (fail any pending picks) */ void grpc_lb_policy_shutdown(grpc_lb_policy *policy); /** Given initial metadata in \a initial_metadata, find an appropriate target for this rpc, and 'return' it by calling \a on_complete after setting \a target. Picking can be asynchronous. Any IO should be done under \a pollset. */ void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, grpc_subchannel **target, grpc_iomgr_closure *on_complete); void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op); void grpc_lb_policy_exit_idle(grpc_lb_policy *policy); void grpc_lb_policy_notify_on_state_change(grpc_lb_policy *policy, grpc_connectivity_state *state, grpc_iomgr_closure *closure); grpc_connectivity_state grpc_lb_policy_check_connectivity( grpc_lb_policy *policy); #endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */ grpc-0.11.1/src/core/client_config/uri_parser.h0000644000175000017500000000362212600663151021570 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H typedef struct { char *scheme; char *authority; char *path; } grpc_uri; /** parse a uri, return NULL on failure */ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors); /** destroy a uri */ void grpc_uri_destroy(grpc_uri *uri); #endif grpc-0.11.1/src/core/client_config/client_config.h0000644000175000017500000000445012600663151022220 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H #include "src/core/client_config/lb_policy.h" /** Total configuration for a client. Provided, and updated, by grpc_resolver */ typedef struct grpc_client_config grpc_client_config; grpc_client_config *grpc_client_config_create(); void grpc_client_config_ref(grpc_client_config *client_config); void grpc_client_config_unref(grpc_client_config *client_config); void grpc_client_config_set_lb_policy(grpc_client_config *client_config, grpc_lb_policy *lb_policy); grpc_lb_policy *grpc_client_config_get_lb_policy( grpc_client_config *client_config); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H */ grpc-0.11.1/src/core/client_config/resolver_factory.h0000644000175000017500000000640112600663151023003 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H #include "src/core/client_config/resolver.h" #include "src/core/client_config/subchannel_factory.h" #include "src/core/client_config/uri_parser.h" typedef struct grpc_resolver_factory grpc_resolver_factory; typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable; /** grpc_resolver provides grpc_client_config objects to grpc_channel objects */ struct grpc_resolver_factory { const grpc_resolver_factory_vtable *vtable; }; struct grpc_resolver_factory_vtable { void (*ref)(grpc_resolver_factory *factory); void (*unref)(grpc_resolver_factory *factory); /** Implementation of grpc_resolver_factory_create_resolver */ grpc_resolver *(*create_resolver)( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory); /** Implementation of grpc_resolver_factory_get_default_authority */ char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri); /** URI scheme that this factory implements */ const char *scheme; }; void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); void grpc_resolver_factory_unref(grpc_resolver_factory *resolver); /** Create a resolver instance for a name */ grpc_resolver *grpc_resolver_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory); /** Return a (freshly allocated with gpr_malloc) string representing the default authority to use for this scheme. */ char *grpc_resolver_factory_get_default_authority( grpc_resolver_factory *factory, grpc_uri *uri); #endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_FACTORY_H */ grpc-0.11.1/src/core/client_config/client_config.c0000644000175000017500000000503112600663151022207 0ustar apollockapollock/* * * 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/client_config/client_config.h" #include #include struct grpc_client_config { gpr_refcount refs; grpc_lb_policy *lb_policy; }; grpc_client_config *grpc_client_config_create() { grpc_client_config *c = gpr_malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); gpr_ref_init(&c->refs, 1); return c; } void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); } void grpc_client_config_unref(grpc_client_config *c) { if (gpr_unref(&c->refs)) { GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config"); gpr_free(c); } } void grpc_client_config_set_lb_policy(grpc_client_config *c, grpc_lb_policy *lb_policy) { if (lb_policy) { GRPC_LB_POLICY_REF(lb_policy, "client_config"); } if (c->lb_policy) { GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config"); } c->lb_policy = lb_policy; } grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) { return c->lb_policy; } grpc-0.11.1/src/core/client_config/lb_policy.c0000644000175000017500000000724112600663151021365 0ustar apollockapollock/* * * 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/client_config/lb_policy.h" void grpc_lb_policy_init(grpc_lb_policy *policy, const grpc_lb_policy_vtable *vtable) { policy->vtable = vtable; gpr_ref_init(&policy->refs, 1); } #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, const char *reason) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p ref %d -> %d %s", policy, (int)policy->refs.count, (int)policy->refs.count + 1, reason); #else void grpc_lb_policy_ref(grpc_lb_policy *policy) { #endif gpr_ref(&policy->refs); } #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line, const char *reason) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p unref %d -> %d %s", policy, (int)policy->refs.count, (int)policy->refs.count - 1, reason); #else void grpc_lb_policy_unref(grpc_lb_policy *policy) { #endif if (gpr_unref(&policy->refs)) { policy->vtable->destroy(policy); } } void grpc_lb_policy_shutdown(grpc_lb_policy *policy) { policy->vtable->shutdown(policy); } void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, grpc_subchannel **target, grpc_iomgr_closure *on_complete) { policy->vtable->pick(policy, pollset, initial_metadata, target, on_complete); } void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op) { policy->vtable->broadcast(policy, op); } void grpc_lb_policy_exit_idle(grpc_lb_policy *policy) { policy->vtable->exit_idle(policy); } void grpc_lb_policy_notify_on_state_change(grpc_lb_policy *policy, grpc_connectivity_state *state, grpc_iomgr_closure *closure) { policy->vtable->notify_on_state_change(policy, state, closure); } grpc_connectivity_state grpc_lb_policy_check_connectivity( grpc_lb_policy *policy) { return policy->vtable->check_connectivity(policy); } grpc-0.11.1/src/core/client_config/subchannel_factory.h0000644000175000017500000000535212600663151023270 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H #include "src/core/channel/channel_stack.h" #include "src/core/client_config/subchannel.h" typedef struct grpc_subchannel_factory grpc_subchannel_factory; typedef struct grpc_subchannel_factory_vtable grpc_subchannel_factory_vtable; /** Constructor for new configured channels. Creating decorators around this type is encouraged to adapt behavior. */ struct grpc_subchannel_factory { const grpc_subchannel_factory_vtable *vtable; }; struct grpc_subchannel_factory_vtable { void (*ref)(grpc_subchannel_factory *factory); void (*unref)(grpc_subchannel_factory *factory); grpc_subchannel *(*create_subchannel)(grpc_subchannel_factory *factory, grpc_subchannel_args *args); }; void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory); void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory); /** Create a new grpc_subchannel */ grpc_subchannel *grpc_subchannel_factory_create_subchannel( grpc_subchannel_factory *factory, grpc_subchannel_args *args); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */ grpc-0.11.1/src/core/client_config/resolver.c0000644000175000017500000000644512600663151021257 0ustar apollockapollock/* * * 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/client_config/resolver.h" void grpc_resolver_init(grpc_resolver *resolver, const grpc_resolver_vtable *vtable) { resolver->vtable = vtable; gpr_ref_init(&resolver->refs, 1); } #ifdef GRPC_RESOLVER_REFCOUNT_DEBUG void grpc_resolver_ref(grpc_resolver *resolver, const char *file, int line, const char *reason) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p ref %d -> %d %s", resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1, reason); #else void grpc_resolver_ref(grpc_resolver *resolver) { #endif gpr_ref(&resolver->refs); } #ifdef GRPC_RESOLVER_REFCOUNT_DEBUG void grpc_resolver_unref(grpc_resolver *resolver, const char *file, int line, const char *reason) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s", resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1, reason); #else void grpc_resolver_unref(grpc_resolver *resolver) { #endif if (gpr_unref(&resolver->refs)) { resolver->vtable->destroy(resolver); } } void grpc_resolver_shutdown(grpc_resolver *resolver) { resolver->vtable->shutdown(resolver); } void grpc_resolver_channel_saw_error(grpc_resolver *resolver, struct sockaddr *failing_address, int failing_address_len) { resolver->vtable->channel_saw_error(resolver, failing_address, failing_address_len); } void grpc_resolver_next(grpc_resolver *resolver, grpc_client_config **target_config, grpc_iomgr_closure *on_complete) { resolver->vtable->next(resolver, target_config, on_complete); } grpc-0.11.1/src/core/client_config/uri_parser.c0000644000175000017500000001141512600663151021562 0ustar apollockapollock/* * * 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/client_config/uri_parser.h" #include #include #include #include static grpc_uri *bad_uri(const char *uri_text, int pos, const char *section, int suppress_errors) { char *line_prefix; int pfx_len; if (!suppress_errors) { gpr_asprintf(&line_prefix, "bad uri.%s: '", section); pfx_len = strlen(line_prefix) + pos; gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text); gpr_free(line_prefix); line_prefix = gpr_malloc(pfx_len + 1); memset(line_prefix, ' ', pfx_len); line_prefix[pfx_len] = 0; gpr_log(GPR_ERROR, "%s^ here", line_prefix); gpr_free(line_prefix); } return NULL; } static char *copy_fragment(const char *src, int begin, int end) { char *out = gpr_malloc(end - begin + 1); memcpy(out, src + begin, end - begin); out[end - begin] = 0; return out; } grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { grpc_uri *uri; int scheme_begin = 0; int scheme_end = -1; int authority_begin = -1; int authority_end = -1; int path_begin = -1; int path_end = -1; int i; for (i = scheme_begin; uri_text[i] != 0; i++) { if (uri_text[i] == ':') { scheme_end = i; break; } if (uri_text[i] >= 'a' && uri_text[i] <= 'z') continue; if (uri_text[i] >= 'A' && uri_text[i] <= 'Z') continue; if (i != scheme_begin) { if (uri_text[i] >= '0' && uri_text[i] <= '9') continue; if (uri_text[i] == '+') continue; if (uri_text[i] == '-') continue; if (uri_text[i] == '.') continue; } break; } if (scheme_end == -1) { return bad_uri(uri_text, i, "scheme", suppress_errors); } if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') { authority_begin = scheme_end + 3; for (i = authority_begin; uri_text[i] != 0 && authority_end == -1; i++) { if (uri_text[i] == '/') { authority_end = i; } if (uri_text[i] == '?') { return bad_uri(uri_text, i, "query_not_supported", suppress_errors); } if (uri_text[i] == '#') { return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors); } } if (authority_end == -1 && uri_text[i] == 0) { authority_end = i; } if (authority_end == -1) { return bad_uri(uri_text, i, "authority", suppress_errors); } /* TODO(ctiller): parse the authority correctly */ path_begin = authority_end; } else { path_begin = scheme_end + 1; } for (i = path_begin; uri_text[i] != 0; i++) { if (uri_text[i] == '?') { return bad_uri(uri_text, i, "query_not_supported", suppress_errors); } if (uri_text[i] == '#') { return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors); } } path_end = i; uri = gpr_malloc(sizeof(*uri)); memset(uri, 0, sizeof(*uri)); uri->scheme = copy_fragment(uri_text, scheme_begin, scheme_end); uri->authority = copy_fragment(uri_text, authority_begin, authority_end); uri->path = copy_fragment(uri_text, path_begin, path_end); return uri; } void grpc_uri_destroy(grpc_uri *uri) { if (!uri) return; gpr_free(uri->scheme); gpr_free(uri->authority); gpr_free(uri->path); gpr_free(uri); } grpc-0.11.1/src/core/client_config/connector.c0000644000175000017500000000410412600663151021376 0ustar apollockapollock/* * * 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/client_config/connector.h" void grpc_connector_ref(grpc_connector *connector) { connector->vtable->ref(connector); } void grpc_connector_unref(grpc_connector *connector) { connector->vtable->unref(connector); } void grpc_connector_connect(grpc_connector *connector, const grpc_connect_in_args *in_args, grpc_connect_out_args *out_args, grpc_iomgr_closure *notify) { connector->vtable->connect(connector, in_args, out_args, notify); } grpc-0.11.1/src/core/client_config/resolver_registry.c0000644000175000017500000001104012600663151023172 0ustar apollockapollock/* * * 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/client_config/resolver_registry.h" #include #include #include #include #define MAX_RESOLVERS 10 static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS]; static int g_number_of_resolvers = 0; static char *g_default_resolver_prefix; void grpc_resolver_registry_init(const char *default_resolver_prefix) { g_number_of_resolvers = 0; g_default_resolver_prefix = gpr_strdup(default_resolver_prefix); } void grpc_resolver_registry_shutdown(void) { int i; for (i = 0; i < g_number_of_resolvers; i++) { grpc_resolver_factory_unref(g_all_of_the_resolvers[i]); } gpr_free(g_default_resolver_prefix); } void grpc_register_resolver_type(grpc_resolver_factory *factory) { int i; for (i = 0; i < g_number_of_resolvers; i++) { GPR_ASSERT(0 != strcmp(factory->vtable->scheme, g_all_of_the_resolvers[i]->vtable->scheme)); } GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS); grpc_resolver_factory_ref(factory); g_all_of_the_resolvers[g_number_of_resolvers++] = factory; } static grpc_resolver_factory *lookup_factory(grpc_uri *uri) { int i; /* handling NULL uri's here simplifies grpc_resolver_create */ if (!uri) return NULL; for (i = 0; i < g_number_of_resolvers; i++) { if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i]->vtable->scheme)) { return g_all_of_the_resolvers[i]; } } return NULL; } static grpc_resolver_factory *resolve_factory(const char *target, grpc_uri **uri) { char *tmp; grpc_resolver_factory *factory = NULL; GPR_ASSERT(uri != NULL); *uri = grpc_uri_parse(target, 1); factory = lookup_factory(*uri); if (factory == NULL) { if (g_default_resolver_prefix != NULL) { grpc_uri_destroy(*uri); gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target); *uri = grpc_uri_parse(tmp, 1); factory = lookup_factory(*uri); if (factory == NULL) { grpc_uri_destroy(grpc_uri_parse(target, 0)); grpc_uri_destroy(grpc_uri_parse(tmp, 0)); gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, tmp); } gpr_free(tmp); } else { grpc_uri_destroy(grpc_uri_parse(target, 0)); gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target); } } return factory; } grpc_resolver *grpc_resolver_create( const char *target, grpc_subchannel_factory *subchannel_factory) { grpc_uri *uri = NULL; grpc_resolver_factory *factory = resolve_factory(target, &uri); grpc_resolver *resolver = grpc_resolver_factory_create_resolver(factory, uri, subchannel_factory); grpc_uri_destroy(uri); return resolver; } char *grpc_get_default_authority(const char *target) { grpc_uri *uri = NULL; grpc_resolver_factory *factory = resolve_factory(target, &uri); char *authority = grpc_resolver_factory_get_default_authority(factory, uri); grpc_uri_destroy(uri); return authority; } grpc-0.11.1/src/core/client_config/subchannel_factory_decorators/0000755000175000017500000000000012600663151025337 5ustar apollockapollockgrpc-0.11.1/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h0000644000175000017500000000427012600663151031316 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H #include "src/core/client_config/subchannel_factory.h" /** Takes a subchannel factory, returns a new one that mutates incoming channel_args by adding a new argument; ownership of input, args is retained by the caller. */ grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args( grpc_subchannel_factory *input, const grpc_channel_args *args); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H \ */ grpc-0.11.1/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c0000644000175000017500000000636112600663151031314 0ustar apollockapollock/* * * 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/client_config/subchannel_factory_decorators/merge_channel_args.h" #include #include "src/core/channel/channel_args.h" typedef struct { grpc_subchannel_factory base; gpr_refcount refs; grpc_subchannel_factory *wrapped; grpc_channel_args *merge_args; } merge_args_factory; static void merge_args_factory_ref(grpc_subchannel_factory *scf) { merge_args_factory *f = (merge_args_factory *)scf; gpr_ref(&f->refs); } static void merge_args_factory_unref(grpc_subchannel_factory *scf) { merge_args_factory *f = (merge_args_factory *)scf; if (gpr_unref(&f->refs)) { grpc_subchannel_factory_unref(f->wrapped); grpc_channel_args_destroy(f->merge_args); gpr_free(f); } } static grpc_subchannel *merge_args_factory_create_subchannel( grpc_subchannel_factory *scf, grpc_subchannel_args *args) { merge_args_factory *f = (merge_args_factory *)scf; grpc_channel_args *final_args = grpc_channel_args_merge(args->args, f->merge_args); grpc_subchannel *s; args->args = final_args; s = grpc_subchannel_factory_create_subchannel(f->wrapped, args); grpc_channel_args_destroy(final_args); return s; } static const grpc_subchannel_factory_vtable merge_args_factory_vtable = { merge_args_factory_ref, merge_args_factory_unref, merge_args_factory_create_subchannel}; grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args( grpc_subchannel_factory *input, const grpc_channel_args *args) { merge_args_factory *f = gpr_malloc(sizeof(*f)); f->base.vtable = &merge_args_factory_vtable; gpr_ref_init(&f->refs, 1); grpc_subchannel_factory_ref(input); f->wrapped = input; f->merge_args = grpc_channel_args_copy(args); return &f->base; } grpc-0.11.1/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h0000644000175000017500000000424112600663151030562 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H #include "src/core/client_config/subchannel_factory.h" /** Takes a subchannel factory, returns a new one that mutates incoming channel_args by adding a new argument; ownership of input, arg is retained by the caller. */ grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg( grpc_subchannel_factory *input, const grpc_arg *arg); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H \ */ grpc-0.11.1/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c0000644000175000017500000000373212600663151030561 0ustar apollockapollock/* * * 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/client_config/subchannel_factory_decorators/add_channel_arg.h" #include "src/core/client_config/subchannel_factory_decorators/merge_channel_args.h" grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg( grpc_subchannel_factory *input, const grpc_arg *arg) { grpc_channel_args args; args.num_args = 1; args.args = (grpc_arg *)arg; return grpc_subchannel_factory_merge_channel_args(input, &args); } grpc-0.11.1/src/core/client_config/subchannel.c0000644000175000017500000005735312600663151021544 0ustar apollockapollock/* * * 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/client_config/subchannel.h" #include #include #include "src/core/channel/channel_args.h" #include "src/core/channel/client_channel.h" #include "src/core/channel/connected_channel.h" #include "src/core/iomgr/alarm.h" #include "src/core/transport/connectivity_state.h" #include "src/core/surface/channel.h" #define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 #define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1 #define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 #define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 #define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 typedef struct { /* all fields protected by subchannel->mu */ /** refcount */ int refs; /** parent subchannel */ grpc_subchannel *subchannel; } connection; typedef struct { grpc_iomgr_closure closure; size_t version; grpc_subchannel *subchannel; grpc_connectivity_state connectivity_state; } state_watcher; typedef struct waiting_for_connect { struct waiting_for_connect *next; grpc_iomgr_closure *notify; grpc_pollset *pollset; grpc_subchannel_call **target; grpc_subchannel *subchannel; grpc_iomgr_closure continuation; } waiting_for_connect; struct grpc_subchannel { grpc_connector *connector; /** non-transport related channel filters */ const grpc_channel_filter **filters; size_t num_filters; /** channel arguments */ grpc_channel_args *args; /** address to connect to */ struct sockaddr *addr; size_t addr_len; /** metadata context */ grpc_mdctx *mdctx; /** master channel - the grpc_channel instance that ultimately owns this channel_data via its channel stack. We occasionally use this to bump the refcount on the master channel to keep ourselves alive through an asynchronous operation. */ grpc_channel *master; /** have we seen a disconnection? */ int disconnected; /** set during connection */ grpc_connect_out_args connecting_result; /** callback for connection finishing */ grpc_iomgr_closure connected; /** pollset_set tracking who's interested in a connection being setup - owned by the master channel (in particular the client_channel filter there-in) */ grpc_pollset_set *pollset_set; /** mutex protecting remaining elements */ gpr_mu mu; /** active connection */ connection *active; /** version number for the active connection */ size_t active_version; /** refcount */ int refs; /** are we connecting */ int connecting; /** things waiting for a connection */ waiting_for_connect *waiting; /** connectivity state tracking */ grpc_connectivity_state_tracker state_tracker; /** next connect attempt time */ gpr_timespec next_attempt; /** amount to backoff each failure */ gpr_timespec backoff_delta; /** do we have an active alarm? */ int have_alarm; /** our alarm */ grpc_alarm alarm; /** current random value */ gpr_uint32 random; }; struct grpc_subchannel_call { connection *connection; gpr_refcount refs; }; #define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) #define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1)) static grpc_subchannel_call *create_call(connection *con); static void connectivity_state_changed_locked(grpc_subchannel *c, const char *reason); static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c); static gpr_timespec compute_connect_deadline(grpc_subchannel *c); static void subchannel_connected(void *subchannel, int iomgr_success); static void subchannel_ref_locked( grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS); static int subchannel_unref_locked( grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT; static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS); static grpc_subchannel *connection_unref_locked( connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT; static void subchannel_destroy(grpc_subchannel *c); #ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG #define SUBCHANNEL_REF_LOCKED(p, r) \ subchannel_ref_locked((p), __FILE__, __LINE__, (r)) #define SUBCHANNEL_UNREF_LOCKED(p, r) \ subchannel_unref_locked((p), __FILE__, __LINE__, (r)) #define CONNECTION_REF_LOCKED(p, r) \ connection_ref_locked((p), __FILE__, __LINE__, (r)) #define CONNECTION_UNREF_LOCKED(p, r) \ connection_unref_locked((p), __FILE__, __LINE__, (r)) #define REF_PASS_ARGS , file, line, reason #define REF_LOG(name, p) \ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \ (name), (p), (p)->refs, (p)->refs + 1, reason) #define UNREF_LOG(name, p) \ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \ (name), (p), (p)->refs, (p)->refs - 1, reason) #else #define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p)) #define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p)) #define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p)) #define CONNECTION_UNREF_LOCKED(p, r) connection_unref_locked((p)) #define REF_PASS_ARGS #define REF_LOG(name, p) \ do { \ } while (0) #define UNREF_LOG(name, p) \ do { \ } while (0) #endif /* * connection implementation */ static void connection_destroy(connection *c) { GPR_ASSERT(c->refs == 0); grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CONNECTION(c)); gpr_free(c); } static void connection_ref_locked( connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { REF_LOG("CONNECTION", c); subchannel_ref_locked(c->subchannel REF_PASS_ARGS); ++c->refs; } static grpc_subchannel *connection_unref_locked( connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { grpc_subchannel *destroy = NULL; UNREF_LOG("CONNECTION", c); if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) { destroy = c->subchannel; } if (--c->refs == 0 && c->subchannel->active != c) { connection_destroy(c); } return destroy; } /* * grpc_subchannel implementation */ static void subchannel_ref_locked( grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { REF_LOG("SUBCHANNEL", c); ++c->refs; } static int subchannel_unref_locked( grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { UNREF_LOG("SUBCHANNEL", c); return --c->refs == 0; } void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { gpr_mu_lock(&c->mu); subchannel_ref_locked(c REF_PASS_ARGS); gpr_mu_unlock(&c->mu); } void grpc_subchannel_unref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { int destroy; gpr_mu_lock(&c->mu); destroy = subchannel_unref_locked(c REF_PASS_ARGS); gpr_mu_unlock(&c->mu); if (destroy) subchannel_destroy(c); } static void subchannel_destroy(grpc_subchannel *c) { if (c->active != NULL) { connection_destroy(c->active); } gpr_free(c->filters); grpc_channel_args_destroy(c->args); gpr_free(c->addr); grpc_mdctx_unref(c->mdctx); grpc_connectivity_state_destroy(&c->state_tracker); grpc_connector_unref(c->connector); gpr_free(c); } void grpc_subchannel_add_interested_party(grpc_subchannel *c, grpc_pollset *pollset) { grpc_pollset_set_add_pollset(c->pollset_set, pollset); } void grpc_subchannel_del_interested_party(grpc_subchannel *c, grpc_pollset *pollset) { grpc_pollset_set_del_pollset(c->pollset_set, pollset); } static gpr_uint32 random_seed() { return (gpr_uint32)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC))); } grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, grpc_subchannel_args *args) { grpc_subchannel *c = gpr_malloc(sizeof(*c)); grpc_channel_element *parent_elem = grpc_channel_stack_last_element( grpc_channel_get_channel_stack(args->master)); memset(c, 0, sizeof(*c)); c->refs = 1; c->connector = connector; grpc_connector_ref(c->connector); c->num_filters = args->filter_count; c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters); memcpy(c->filters, args->filters, sizeof(grpc_channel_filter *) * c->num_filters); c->addr = gpr_malloc(args->addr_len); memcpy(c->addr, args->addr, args->addr_len); c->addr_len = args->addr_len; c->args = grpc_channel_args_copy(args->args); c->mdctx = args->mdctx; c->master = args->master; c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem); c->random = random_seed(); grpc_mdctx_ref(c->mdctx); grpc_iomgr_closure_init(&c->connected, subchannel_connected, c); grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, "subchannel"); gpr_mu_init(&c->mu); return c; } static void continue_connect(grpc_subchannel *c) { grpc_connect_in_args args; args.interested_parties = c->pollset_set; args.addr = c->addr; args.addr_len = c->addr_len; args.deadline = compute_connect_deadline(c); args.channel_args = c->args; args.metadata_context = c->mdctx; grpc_connector_connect(c->connector, &args, &c->connecting_result, &c->connected); } static void start_connect(grpc_subchannel *c) { c->backoff_delta = gpr_time_from_seconds( GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS, GPR_TIMESPAN); c->next_attempt = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), c->backoff_delta); continue_connect(c); } static void continue_creating_call(void *arg, int iomgr_success) { waiting_for_connect *w4c = arg; grpc_subchannel_del_interested_party(w4c->subchannel, w4c->pollset); grpc_subchannel_create_call(w4c->subchannel, w4c->pollset, w4c->target, w4c->notify); GRPC_SUBCHANNEL_UNREF(w4c->subchannel, "waiting_for_connect"); gpr_free(w4c); } void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset, grpc_subchannel_call **target, grpc_iomgr_closure *notify) { connection *con; gpr_mu_lock(&c->mu); if (c->active != NULL) { con = c->active; CONNECTION_REF_LOCKED(con, "call"); gpr_mu_unlock(&c->mu); *target = create_call(con); notify->cb(notify->cb_arg, 1); } else { waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c)); w4c->next = c->waiting; w4c->notify = notify; w4c->pollset = pollset; w4c->target = target; w4c->subchannel = c; /* released when clearing w4c */ SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect"); grpc_iomgr_closure_init(&w4c->continuation, continue_creating_call, w4c); c->waiting = w4c; grpc_subchannel_add_interested_party(c, pollset); if (!c->connecting) { c->connecting = 1; connectivity_state_changed_locked(c, "create_call"); /* released by connection */ SUBCHANNEL_REF_LOCKED(c, "connecting"); GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting"); gpr_mu_unlock(&c->mu); start_connect(c); } else { gpr_mu_unlock(&c->mu); } } } grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { grpc_connectivity_state state; gpr_mu_lock(&c->mu); state = grpc_connectivity_state_check(&c->state_tracker); gpr_mu_unlock(&c->mu); return state; } void grpc_subchannel_notify_on_state_change(grpc_subchannel *c, grpc_connectivity_state *state, grpc_iomgr_closure *notify) { int do_connect = 0; gpr_mu_lock(&c->mu); if (grpc_connectivity_state_notify_on_state_change(&c->state_tracker, state, notify)) { do_connect = 1; c->connecting = 1; /* released by connection */ SUBCHANNEL_REF_LOCKED(c, "connecting"); GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting"); connectivity_state_changed_locked(c, "state_change"); } gpr_mu_unlock(&c->mu); if (do_connect) { start_connect(c); } } void grpc_subchannel_process_transport_op(grpc_subchannel *c, grpc_transport_op *op) { connection *con = NULL; grpc_subchannel *destroy; int cancel_alarm = 0; gpr_mu_lock(&c->mu); if (op->disconnect) { c->disconnected = 1; connectivity_state_changed_locked(c, "disconnect"); if (c->have_alarm) { cancel_alarm = 1; } } if (c->active != NULL) { con = c->active; CONNECTION_REF_LOCKED(con, "transport-op"); } gpr_mu_unlock(&c->mu); if (con != NULL) { grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con); grpc_channel_element *top_elem = grpc_channel_stack_element(channel_stack, 0); top_elem->filter->start_transport_op(top_elem, op); gpr_mu_lock(&c->mu); destroy = CONNECTION_UNREF_LOCKED(con, "transport-op"); gpr_mu_unlock(&c->mu); if (destroy) { subchannel_destroy(destroy); } } if (cancel_alarm) { grpc_alarm_cancel(&c->alarm); } } static void on_state_changed(void *p, int iomgr_success) { state_watcher *sw = p; grpc_subchannel *c = sw->subchannel; gpr_mu *mu = &c->mu; int destroy; grpc_transport_op op; grpc_channel_element *elem; connection *destroy_connection = NULL; gpr_mu_lock(mu); /* if we failed or there is a version number mismatch, just leave this closure */ if (!iomgr_success || sw->subchannel->active_version != sw->version) { goto done; } switch (sw->connectivity_state) { case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_READY: case GRPC_CHANNEL_IDLE: /* all is still good: keep watching */ memset(&op, 0, sizeof(op)); op.connectivity_state = &sw->connectivity_state; op.on_connectivity_state_change = &sw->closure; elem = grpc_channel_stack_element( CHANNEL_STACK_FROM_CONNECTION(c->active), 0); elem->filter->start_transport_op(elem, &op); /* early out */ gpr_mu_unlock(mu); return; case GRPC_CHANNEL_FATAL_FAILURE: case GRPC_CHANNEL_TRANSIENT_FAILURE: /* things have gone wrong, deactivate and enter idle */ if (sw->subchannel->active->refs == 0) { destroy_connection = sw->subchannel->active; } sw->subchannel->active = NULL; grpc_connectivity_state_set( &c->state_tracker, c->disconnected ? GRPC_CHANNEL_FATAL_FAILURE : GRPC_CHANNEL_TRANSIENT_FAILURE, "connection_failed"); break; } done: connectivity_state_changed_locked(c, "transport_state_changed"); destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher"); gpr_free(sw); gpr_mu_unlock(mu); if (destroy) { subchannel_destroy(c); } if (destroy_connection != NULL) { connection_destroy(destroy_connection); } } static void publish_transport(grpc_subchannel *c) { size_t channel_stack_size; connection *con; grpc_channel_stack *stk; size_t num_filters; const grpc_channel_filter **filters; waiting_for_connect *w4c; grpc_transport_op op; state_watcher *sw; connection *destroy_connection = NULL; grpc_channel_element *elem; /* build final filter list */ num_filters = c->num_filters + c->connecting_result.num_filters + 1; filters = gpr_malloc(sizeof(*filters) * num_filters); memcpy(filters, c->filters, sizeof(*filters) * c->num_filters); memcpy(filters + c->num_filters, c->connecting_result.filters, sizeof(*filters) * c->connecting_result.num_filters); filters[num_filters - 1] = &grpc_connected_channel_filter; /* construct channel stack */ channel_stack_size = grpc_channel_stack_size(filters, num_filters); con = gpr_malloc(sizeof(connection) + channel_stack_size); stk = (grpc_channel_stack *)(con + 1); con->refs = 0; con->subchannel = c; grpc_channel_stack_init(filters, num_filters, c->master, c->args, c->mdctx, stk); grpc_connected_channel_bind_transport(stk, c->connecting_result.transport); gpr_free(c->connecting_result.filters); memset(&c->connecting_result, 0, sizeof(c->connecting_result)); /* initialize state watcher */ sw = gpr_malloc(sizeof(*sw)); grpc_iomgr_closure_init(&sw->closure, on_state_changed, sw); sw->subchannel = c; sw->connectivity_state = GRPC_CHANNEL_READY; gpr_mu_lock(&c->mu); if (c->disconnected) { gpr_mu_unlock(&c->mu); gpr_free(sw); gpr_free(filters); grpc_channel_stack_destroy(stk); GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting"); GRPC_SUBCHANNEL_UNREF(c, "connecting"); return; } /* publish */ if (c->active != NULL && c->active->refs == 0) { destroy_connection = c->active; } c->active = con; c->active_version++; sw->version = c->active_version; c->connecting = 0; /* watch for changes; subchannel ref for connecting is donated to the state watcher */ memset(&op, 0, sizeof(op)); op.connectivity_state = &sw->connectivity_state; op.on_connectivity_state_change = &sw->closure; op.bind_pollset_set = c->pollset_set; SUBCHANNEL_REF_LOCKED(c, "state_watcher"); GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting"); GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting")); elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0); elem->filter->start_transport_op(elem, &op); /* signal completion */ connectivity_state_changed_locked(c, "connected"); while ((w4c = c->waiting)) { c->waiting = w4c->next; grpc_iomgr_add_callback(&w4c->continuation); } gpr_mu_unlock(&c->mu); gpr_free(filters); if (destroy_connection != NULL) { connection_destroy(destroy_connection); } } /* Generate a random number between 0 and 1. */ static double generate_uniform_random_number(grpc_subchannel *c) { c->random = (1103515245 * c->random + 12345) % ((gpr_uint32)1 << 31); return c->random / (double)((gpr_uint32)1 << 31); } /* Update backoff_delta and next_attempt in subchannel */ static void update_reconnect_parameters(grpc_subchannel *c) { gpr_int32 backoff_delta_millis, jitter; gpr_int32 max_backoff_millis = GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000; double jitter_range; backoff_delta_millis = (gpr_int32)(gpr_time_to_millis(c->backoff_delta) * GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER); if (backoff_delta_millis > max_backoff_millis) { backoff_delta_millis = max_backoff_millis; } c->backoff_delta = gpr_time_from_millis(backoff_delta_millis, GPR_TIMESPAN); c->next_attempt = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), c->backoff_delta); jitter_range = GRPC_SUBCHANNEL_RECONNECT_JITTER * backoff_delta_millis; jitter = (gpr_int32)((2 * generate_uniform_random_number(c) - 1) * jitter_range); c->next_attempt = gpr_time_add(c->next_attempt, gpr_time_from_millis(jitter, GPR_TIMESPAN)); } static void on_alarm(void *arg, int iomgr_success) { grpc_subchannel *c = arg; gpr_mu_lock(&c->mu); c->have_alarm = 0; if (c->disconnected) { iomgr_success = 0; } connectivity_state_changed_locked(c, "alarm"); gpr_mu_unlock(&c->mu); if (iomgr_success) { update_reconnect_parameters(c); continue_connect(c); } else { GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting"); GRPC_SUBCHANNEL_UNREF(c, "connecting"); } } static void subchannel_connected(void *arg, int iomgr_success) { grpc_subchannel *c = arg; if (c->connecting_result.transport != NULL) { publish_transport(c); } else { gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_mu_lock(&c->mu); GPR_ASSERT(!c->have_alarm); c->have_alarm = 1; connectivity_state_changed_locked(c, "connect_failed"); grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, now); gpr_mu_unlock(&c->mu); } } static gpr_timespec compute_connect_deadline(grpc_subchannel *c) { gpr_timespec current_deadline = gpr_time_add(c->next_attempt, c->backoff_delta); gpr_timespec min_deadline = gpr_time_add( gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS, GPR_TIMESPAN)); return gpr_time_cmp(current_deadline, min_deadline) > 0 ? current_deadline : min_deadline; } static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) { if (c->disconnected) { return GRPC_CHANNEL_FATAL_FAILURE; } if (c->connecting) { if (c->have_alarm) { return GRPC_CHANNEL_TRANSIENT_FAILURE; } return GRPC_CHANNEL_CONNECTING; } if (c->active) { return GRPC_CHANNEL_READY; } return GRPC_CHANNEL_IDLE; } static void connectivity_state_changed_locked(grpc_subchannel *c, const char *reason) { grpc_connectivity_state current = compute_connectivity_locked(c); grpc_connectivity_state_set(&c->state_tracker, current, reason); } /* * grpc_subchannel_call implementation */ void grpc_subchannel_call_ref( grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { gpr_ref(&c->refs); } void grpc_subchannel_call_unref( grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { if (gpr_unref(&c->refs)) { gpr_mu *mu = &c->connection->subchannel->mu; grpc_subchannel *destroy; grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c)); gpr_mu_lock(mu); destroy = CONNECTION_UNREF_LOCKED(c->connection, "call"); gpr_mu_unlock(mu); gpr_free(c); if (destroy != NULL) { subchannel_destroy(destroy); } } } char *grpc_subchannel_call_get_peer(grpc_subchannel_call *call) { grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); return top_elem->filter->get_peer(top_elem); } void grpc_subchannel_call_process_op(grpc_subchannel_call *call, grpc_transport_stream_op *op) { grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); top_elem->filter->start_transport_stream_op(top_elem, op); } grpc_subchannel_call *create_call(connection *con) { grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); grpc_subchannel_call *call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call); call->connection = con; gpr_ref_init(&call->refs, 1); grpc_call_stack_init(chanstk, NULL, NULL, callstk); return call; } grpc-0.11.1/src/core/json/0000755000175000017500000000000012600663151015407 5ustar apollockapollockgrpc-0.11.1/src/core/json/json_writer.h0000644000175000017500000001040512600663151020125 0ustar apollockapollock/* * * 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. * */ /* The idea of the writer is basically symmetrical of the reader. While the * reader emits various calls to your code, the writer takes basically the * same calls and emit json out of it. It doesn't try to make any check on * the order of the calls you do on it. Meaning you can theorically force * it to generate invalid json. * * Also, unlike the reader, the writer expects UTF-8 encoded input strings. * These strings will be UTF-8 validated, and any invalid character will * cut the conversion short, before any invalid UTF-8 sequence, thus forming * a valid UTF-8 string overall. */ #ifndef GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H #define GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H #include #include "src/core/json/json_common.h" typedef struct grpc_json_writer_vtable { /* Adds a character to the output stream. */ void (*output_char)(void* userdata, char); /* Adds a zero-terminated string to the output stream. */ void (*output_string)(void* userdata, const char* str); /* Adds a fixed-length string to the output stream. */ void (*output_string_with_len)(void* userdata, const char* str, size_t len); } grpc_json_writer_vtable; typedef struct grpc_json_writer { void* userdata; grpc_json_writer_vtable* vtable; int indent; int depth; int container_empty; int got_key; } grpc_json_writer; /* Call this to initialize your writer structure. The indent parameter is * specifying the number of spaces to use for indenting the output. If you * use indent=0, then the output will not have any newlines either, thus * emitting a condensed json output. */ void grpc_json_writer_init(grpc_json_writer* writer, int indent, grpc_json_writer_vtable* vtable, void* userdata); /* Signals the beginning of a container. */ void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type); /* Signals the end of a container. */ void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type); /* Writes down an object key for the next value. */ void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string); /* Sets a raw value. Useful for numbers. */ void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string); /* Sets a raw value with its length. Useful for values like true or false. */ void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len); /* Sets a string value. It'll be escaped, and utf-8 validated. */ void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string); #endif /* GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H */ grpc-0.11.1/src/core/json/json.h0000644000175000017500000000656112600663151016541 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_JSON_JSON_H #define GRPC_INTERNAL_CORE_JSON_JSON_H #include #include "src/core/json/json_common.h" /* A tree-like structure to hold json values. The key and value pointers * are not owned by it. */ typedef struct grpc_json { struct grpc_json* next; struct grpc_json* prev; struct grpc_json* child; struct grpc_json* parent; grpc_json_type type; const char* key; const char* value; } grpc_json; /* The next two functions are going to parse the input string, and * modify it in the process, in order to use its space to store * all of the keys and values for the returned object tree. * * They assume UTF-8 input stream, and will output UTF-8 encoded * strings in the tree. The input stream's UTF-8 isn't validated, * as in, what you input is what you get as an output. * * All the keys and values in the grpc_json objects will be strings * pointing at your input buffer. * * Delete the allocated tree afterward using grpc_json_destroy(). */ grpc_json* grpc_json_parse_string_with_len(char* input, size_t size); grpc_json* grpc_json_parse_string(char* input); /* This function will create a new string using gpr_realloc, and will * deserialize the grpc_json tree into it. It'll be zero-terminated, * but will be allocated in chunks of 256 bytes. * * The indent parameter controls the way the output is formatted. * If indent is 0, then newlines will be suppressed as well, and the * output will be condensed at its maximum. */ char* grpc_json_dump_to_string(grpc_json* json, int indent); /* Use these to create or delete a grpc_json object. * Deletion is recursive. We will not attempt to free any of the strings * in any of the objects of that tree. */ grpc_json* grpc_json_create(grpc_json_type type); void grpc_json_destroy(grpc_json* json); #endif /* GRPC_INTERNAL_CORE_JSON_JSON_H */ grpc-0.11.1/src/core/json/json.c0000644000175000017500000000413712600663151016531 0ustar apollockapollock/* * * 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 #include #include "src/core/json/json.h" grpc_json *grpc_json_create(grpc_json_type type) { grpc_json *json = gpr_malloc(sizeof(*json)); memset(json, 0, sizeof(*json)); json->type = type; return json; } void grpc_json_destroy(grpc_json *json) { while (json->child) { grpc_json_destroy(json->child); } if (json->next) { json->next->prev = json->prev; } if (json->prev) { json->prev->next = json->next; } else if (json->parent) { json->parent->child = json->next; } gpr_free(json); } grpc-0.11.1/src/core/json/json_writer.c0000644000175000017500000002241112600663151020120 0ustar apollockapollock/* * * 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 #include #include "src/core/json/json_writer.h" static void json_writer_output_char(grpc_json_writer* writer, char c) { writer->vtable->output_char(writer->userdata, c); } static void json_writer_output_string(grpc_json_writer* writer, const char* str) { writer->vtable->output_string(writer->userdata, str); } static void json_writer_output_string_with_len(grpc_json_writer* writer, const char* str, size_t len) { writer->vtable->output_string_with_len(writer->userdata, str, len); } void grpc_json_writer_init(grpc_json_writer* writer, int indent, grpc_json_writer_vtable* vtable, void* userdata) { memset(writer, 0, sizeof(*writer)); writer->container_empty = 1; writer->indent = indent; writer->vtable = vtable; writer->userdata = userdata; } static void json_writer_output_indent(grpc_json_writer* writer) { static const char spacesstr[] = " " " " " " " "; unsigned spaces = (unsigned)(writer->depth * writer->indent); if (writer->indent == 0) return; if (writer->got_key) { json_writer_output_char(writer, ' '); return; } while (spaces >= (sizeof(spacesstr) - 1)) { json_writer_output_string_with_len(writer, spacesstr, sizeof(spacesstr) - 1); spaces -= (unsigned)(sizeof(spacesstr) - 1); } if (spaces == 0) return; json_writer_output_string_with_len( writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces); } static void json_writer_value_end(grpc_json_writer* writer) { if (writer->container_empty) { writer->container_empty = 0; if ((writer->indent == 0) || (writer->depth == 0)) return; json_writer_output_char(writer, '\n'); } else { json_writer_output_char(writer, ','); if (writer->indent == 0) return; json_writer_output_char(writer, '\n'); } } static void json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) { static const char hex[] = "0123456789abcdef"; json_writer_output_string_with_len(writer, "\\u", 2); json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); json_writer_output_char(writer, hex[(utf16)&0x0f]); } static void json_writer_escape_string(grpc_json_writer* writer, const char* string) { json_writer_output_char(writer, '"'); for (;;) { gpr_uint8 c = (gpr_uint8)*string++; if (c == 0) { break; } else if ((c >= 32) && (c <= 126)) { if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); json_writer_output_char(writer, (char)c); } else if ((c < 32) || (c == 127)) { switch (c) { case '\b': json_writer_output_string_with_len(writer, "\\b", 2); break; case '\f': json_writer_output_string_with_len(writer, "\\f", 2); break; case '\n': json_writer_output_string_with_len(writer, "\\n", 2); break; case '\r': json_writer_output_string_with_len(writer, "\\r", 2); break; case '\t': json_writer_output_string_with_len(writer, "\\t", 2); break; default: json_writer_escape_utf16(writer, c); break; } } else { gpr_uint32 utf32 = 0; int extra = 0; int i; int valid = 1; if ((c & 0xe0) == 0xc0) { utf32 = c & 0x1f; extra = 1; } else if ((c & 0xf0) == 0xe0) { utf32 = c & 0x0f; extra = 2; } else if ((c & 0xf8) == 0xf0) { utf32 = c & 0x07; extra = 3; } else { break; } for (i = 0; i < extra; i++) { utf32 <<= 6; c = (gpr_uint8)(*string++); /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */ if ((c & 0xc0) != 0x80) { valid = 0; break; } utf32 |= c & 0x3f; } if (!valid) break; /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam. * Any other range is technically reserved for future usage, so if we * don't want the software to break in the future, we have to allow * anything else. The first non-unicode character is 0x110000. */ if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000)) break; if (utf32 >= 0x10000) { /* If utf32 contains a character that is above 0xffff, it needs to be * broken down into a utf-16 surrogate pair. A surrogate pair is first * a high surrogate, followed by a low surrogate. Each surrogate holds * 10 bits of usable data, thus allowing a total of 20 bits of data. * The high surrogate marker is 0xd800, while the low surrogate marker * is 0xdc00. The low 10 bits of each will be the usable data. * * After re-combining the 20 bits of data, one has to add 0x10000 to * the resulting value, in order to obtain the original character. * This is obviously because the range 0x0000 - 0xffff can be written * without any special trick. * * Since 0x10ffff is the highest allowed character, we're working in * the range 0x00000 - 0xfffff after we decrement it by 0x10000. * That range is exactly 20 bits. */ utf32 -= 0x10000; json_writer_escape_utf16(writer, (gpr_uint16)(0xd800 | (utf32 >> 10))); json_writer_escape_utf16(writer, (gpr_uint16)(0xdc00 | (utf32 & 0x3ff))); } else { json_writer_escape_utf16(writer, (gpr_uint16)utf32); } } } json_writer_output_char(writer, '"'); } void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '['); writer->container_empty = 1; writer->got_key = 0; writer->depth++; } void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type) { if (writer->indent && !writer->container_empty) json_writer_output_char(writer, '\n'); writer->depth--; if (!writer->container_empty) json_writer_output_indent(writer); json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']'); writer->container_empty = 0; writer->got_key = 0; } void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string) { json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_escape_string(writer, string); json_writer_output_char(writer, ':'); writer->got_key = 1; } void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_output_string(writer, string); writer->got_key = 0; } void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_output_string_with_len(writer, string, len); writer->got_key = 0; } void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_escape_string(writer, string); writer->got_key = 0; } grpc-0.11.1/src/core/json/json_reader.h0000644000175000017500000001471412600663151020062 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_JSON_JSON_READER_H #define GRPC_INTERNAL_CORE_JSON_JSON_READER_H #include #include "src/core/json/json_common.h" typedef enum { GRPC_JSON_STATE_OBJECT_KEY_BEGIN, GRPC_JSON_STATE_OBJECT_KEY_STRING, GRPC_JSON_STATE_OBJECT_KEY_END, GRPC_JSON_STATE_VALUE_BEGIN, GRPC_JSON_STATE_VALUE_STRING, GRPC_JSON_STATE_STRING_ESCAPE, GRPC_JSON_STATE_STRING_ESCAPE_U1, GRPC_JSON_STATE_STRING_ESCAPE_U2, GRPC_JSON_STATE_STRING_ESCAPE_U3, GRPC_JSON_STATE_STRING_ESCAPE_U4, GRPC_JSON_STATE_VALUE_NUMBER, GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL, GRPC_JSON_STATE_VALUE_NUMBER_ZERO, GRPC_JSON_STATE_VALUE_NUMBER_DOT, GRPC_JSON_STATE_VALUE_NUMBER_E, GRPC_JSON_STATE_VALUE_NUMBER_EPM, GRPC_JSON_STATE_VALUE_TRUE_R, GRPC_JSON_STATE_VALUE_TRUE_U, GRPC_JSON_STATE_VALUE_TRUE_E, GRPC_JSON_STATE_VALUE_FALSE_A, GRPC_JSON_STATE_VALUE_FALSE_L, GRPC_JSON_STATE_VALUE_FALSE_S, GRPC_JSON_STATE_VALUE_FALSE_E, GRPC_JSON_STATE_VALUE_NULL_U, GRPC_JSON_STATE_VALUE_NULL_L1, GRPC_JSON_STATE_VALUE_NULL_L2, GRPC_JSON_STATE_VALUE_END, GRPC_JSON_STATE_END } grpc_json_reader_state; enum { /* The first non-unicode value is 0x110000. But let's pick * a value high enough to start our error codes from. These * values are safe to return from the read_char function. */ GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0, GRPC_JSON_READ_CHAR_EAGAIN, GRPC_JSON_READ_CHAR_ERROR }; struct grpc_json_reader; typedef struct grpc_json_reader_vtable { /* Clears your internal string scratchpad. */ void (*string_clear)(void* userdata); /* Adds a char to the string scratchpad. */ void (*string_add_char)(void* userdata, gpr_uint32 c); /* Adds a utf32 char to the string scratchpad. */ void (*string_add_utf32)(void* userdata, gpr_uint32 c); /* Reads a character from your input. May be utf-8, 16 or 32. */ gpr_uint32 (*read_char)(void* userdata); /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */ void (*container_begins)(void* userdata, grpc_json_type type); /* Ends the current container. Must return the type of its parent. */ grpc_json_type (*container_ends)(void* userdata); /* Your internal string scratchpad is an object's key. */ void (*set_key)(void* userdata); /* Your internal string scratchpad is a string value. */ void (*set_string)(void* userdata); /* Your internal string scratchpad is a numerical value. Return 1 if valid. */ int (*set_number)(void* userdata); /* Sets the values true, false or null. */ void (*set_true)(void* userdata); void (*set_false)(void* userdata); void (*set_null)(void* userdata); } grpc_json_reader_vtable; typedef struct grpc_json_reader { /* That structure is fully private, and initialized by grpc_json_reader_init. * The definition is public so you can put it on your stack. */ void* userdata; grpc_json_reader_vtable* vtable; int depth; int in_object; int in_array; int escaped_string_was_key; int container_just_begun; gpr_uint16 unicode_char, unicode_high_surrogate; grpc_json_reader_state state; } grpc_json_reader; /* The return type of the parser. */ typedef enum { GRPC_JSON_DONE, /* The parser finished successfully. */ GRPC_JSON_EAGAIN, /* The parser yields to get more data. */ GRPC_JSON_READ_ERROR, /* The parser passes through a read error. */ GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */ GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */ } grpc_json_reader_status; /* Call this function to start parsing the input. It will return the following: * . GRPC_JSON_DONE if the input got eof, and the parsing finished * successfully. * . GRPC_JSON_EAGAIN if the read_char function returned again. Call the * parser again as needed. It is okay to call the parser in polling mode, * although a bit dull. * . GRPC_JSON_READ_ERROR if the read_char function returned an error. The * state isn't broken however, and the function can be called again if the * error has been corrected. But please use the EAGAIN feature instead for * consistency. * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid. * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid * internal state. */ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader); /* Call this function to initialize the reader structure. */ void grpc_json_reader_init(grpc_json_reader* reader, grpc_json_reader_vtable* vtable, void* userdata); /* You may call this from the read_char callback if you don't know where is the * end of your input stream, and you'd like the json reader to hint you that it * has completed reading its input, so you can return an EOF to it. Note that * there might still be trailing whitespaces after that point. */ int grpc_json_reader_is_complete(grpc_json_reader* reader); #endif /* GRPC_INTERNAL_CORE_JSON_JSON_READER_H */ grpc-0.11.1/src/core/json/json_common.h0000644000175000017500000000361612600663151020107 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H #define GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H /* The various json types. */ typedef enum { GRPC_JSON_OBJECT, GRPC_JSON_ARRAY, GRPC_JSON_STRING, GRPC_JSON_NUMBER, GRPC_JSON_TRUE, GRPC_JSON_FALSE, GRPC_JSON_NULL, GRPC_JSON_TOP_LEVEL } grpc_json_type; #endif /* GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H */ grpc-0.11.1/src/core/json/json_reader.c0000644000175000017500000005436512600663151020063 0ustar apollockapollock/* * * 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 #include #include "src/core/json/json_reader.h" static void json_reader_string_clear(grpc_json_reader* reader) { reader->vtable->string_clear(reader->userdata); } static void json_reader_string_add_char(grpc_json_reader* reader, gpr_uint32 c) { reader->vtable->string_add_char(reader->userdata, c); } static void json_reader_string_add_utf32(grpc_json_reader* reader, gpr_uint32 utf32) { reader->vtable->string_add_utf32(reader->userdata, utf32); } static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) { return reader->vtable->read_char(reader->userdata); } static void json_reader_container_begins(grpc_json_reader* reader, grpc_json_type type) { reader->vtable->container_begins(reader->userdata, type); } static grpc_json_type grpc_json_reader_container_ends( grpc_json_reader* reader) { return reader->vtable->container_ends(reader->userdata); } static void json_reader_set_key(grpc_json_reader* reader) { reader->vtable->set_key(reader->userdata); } static void json_reader_set_string(grpc_json_reader* reader) { reader->vtable->set_string(reader->userdata); } static int json_reader_set_number(grpc_json_reader* reader) { return reader->vtable->set_number(reader->userdata); } static void json_reader_set_true(grpc_json_reader* reader) { reader->vtable->set_true(reader->userdata); } static void json_reader_set_false(grpc_json_reader* reader) { reader->vtable->set_false(reader->userdata); } static void json_reader_set_null(grpc_json_reader* reader) { reader->vtable->set_null(reader->userdata); } /* Call this function to initialize the reader structure. */ void grpc_json_reader_init(grpc_json_reader* reader, grpc_json_reader_vtable* vtable, void* userdata) { memset(reader, 0, sizeof(*reader)); reader->vtable = vtable; reader->userdata = userdata; json_reader_string_clear(reader); reader->state = GRPC_JSON_STATE_VALUE_BEGIN; } int grpc_json_reader_is_complete(grpc_json_reader* reader) { return ((reader->depth == 0) && ((reader->state == GRPC_JSON_STATE_END) || (reader->state == GRPC_JSON_STATE_VALUE_END))); } grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { gpr_uint32 c, success; /* This state-machine is a strict implementation of ECMA-404 */ for (;;) { c = grpc_json_reader_read_char(reader); switch (c) { /* Let's process the error cases first. */ case GRPC_JSON_READ_CHAR_ERROR: return GRPC_JSON_READ_ERROR; case GRPC_JSON_READ_CHAR_EAGAIN: return GRPC_JSON_EAGAIN; case GRPC_JSON_READ_CHAR_EOF: if (grpc_json_reader_is_complete(reader)) { return GRPC_JSON_DONE; } else { return GRPC_JSON_PARSE_ERROR; } break; /* Processing whitespaces. */ case ' ': case '\t': case '\n': case '\r': switch (reader->state) { case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: case GRPC_JSON_STATE_OBJECT_KEY_END: case GRPC_JSON_STATE_VALUE_BEGIN: case GRPC_JSON_STATE_VALUE_END: case GRPC_JSON_STATE_END: break; case GRPC_JSON_STATE_OBJECT_KEY_STRING: case GRPC_JSON_STATE_VALUE_STRING: if (c != ' ') return GRPC_JSON_PARSE_ERROR; if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); break; case GRPC_JSON_STATE_VALUE_NUMBER: case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: case GRPC_JSON_STATE_VALUE_NUMBER_EPM: success = (gpr_uint32)json_reader_set_number(reader); if (!success) return GRPC_JSON_PARSE_ERROR; json_reader_string_clear(reader); reader->state = GRPC_JSON_STATE_VALUE_END; break; default: return GRPC_JSON_PARSE_ERROR; } break; /* Value, object or array terminations. */ case ',': case '}': case ']': switch (reader->state) { case GRPC_JSON_STATE_OBJECT_KEY_STRING: case GRPC_JSON_STATE_VALUE_STRING: if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); break; case GRPC_JSON_STATE_VALUE_NUMBER: case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: case GRPC_JSON_STATE_VALUE_NUMBER_EPM: success = (gpr_uint32)json_reader_set_number(reader); if (!success) return GRPC_JSON_PARSE_ERROR; json_reader_string_clear(reader); reader->state = GRPC_JSON_STATE_VALUE_END; /* The missing break here is intentional. */ case GRPC_JSON_STATE_VALUE_END: case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: case GRPC_JSON_STATE_VALUE_BEGIN: if (c == ',') { if (reader->state != GRPC_JSON_STATE_VALUE_END) { return GRPC_JSON_PARSE_ERROR; } if (reader->in_object) { reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; } else { reader->state = GRPC_JSON_STATE_VALUE_BEGIN; } } else { if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR; if ((c == '}') && !reader->in_object) { return GRPC_JSON_PARSE_ERROR; } if ((c == '}') && (reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) && !reader->container_just_begun) { return GRPC_JSON_PARSE_ERROR; } if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR; if ((c == ']') && (reader->state == GRPC_JSON_STATE_VALUE_BEGIN) && !reader->container_just_begun) { return GRPC_JSON_PARSE_ERROR; } reader->state = GRPC_JSON_STATE_VALUE_END; switch (grpc_json_reader_container_ends(reader)) { case GRPC_JSON_OBJECT: reader->in_object = 1; reader->in_array = 0; break; case GRPC_JSON_ARRAY: reader->in_object = 0; reader->in_array = 1; break; case GRPC_JSON_TOP_LEVEL: if (reader->depth != 0) return GRPC_JSON_INTERNAL_ERROR; reader->in_object = 0; reader->in_array = 0; reader->state = GRPC_JSON_STATE_END; break; default: return GRPC_JSON_INTERNAL_ERROR; } } break; default: return GRPC_JSON_PARSE_ERROR; } break; /* In-string escaping. */ case '\\': switch (reader->state) { case GRPC_JSON_STATE_OBJECT_KEY_STRING: reader->escaped_string_was_key = 1; reader->state = GRPC_JSON_STATE_STRING_ESCAPE; break; case GRPC_JSON_STATE_VALUE_STRING: reader->escaped_string_was_key = 0; reader->state = GRPC_JSON_STATE_STRING_ESCAPE; break; /* This is the \\ case. */ case GRPC_JSON_STATE_STRING_ESCAPE: if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, '\\'); if (reader->escaped_string_was_key) { reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { reader->state = GRPC_JSON_STATE_VALUE_STRING; } break; default: return GRPC_JSON_PARSE_ERROR; } break; default: reader->container_just_begun = 0; switch (reader->state) { case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: if (c != '"') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; break; case GRPC_JSON_STATE_OBJECT_KEY_STRING: if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; if (c == '"') { reader->state = GRPC_JSON_STATE_OBJECT_KEY_END; json_reader_set_key(reader); json_reader_string_clear(reader); } else { if (c <= 0x001f) return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); } break; case GRPC_JSON_STATE_VALUE_STRING: if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; if (c == '"') { reader->state = GRPC_JSON_STATE_VALUE_END; json_reader_set_string(reader); json_reader_string_clear(reader); } else { if (c < 32) return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); } break; case GRPC_JSON_STATE_OBJECT_KEY_END: if (c != ':') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_BEGIN; break; case GRPC_JSON_STATE_VALUE_BEGIN: switch (c) { case 't': reader->state = GRPC_JSON_STATE_VALUE_TRUE_R; break; case 'f': reader->state = GRPC_JSON_STATE_VALUE_FALSE_A; break; case 'n': reader->state = GRPC_JSON_STATE_VALUE_NULL_U; break; case '"': reader->state = GRPC_JSON_STATE_VALUE_STRING; break; case '0': json_reader_string_add_char(reader, c); reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': json_reader_string_add_char(reader, c); reader->state = GRPC_JSON_STATE_VALUE_NUMBER; break; case '{': reader->container_just_begun = 1; json_reader_container_begins(reader, GRPC_JSON_OBJECT); reader->depth++; reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; reader->in_object = 1; reader->in_array = 0; break; case '[': reader->container_just_begun = 1; json_reader_container_begins(reader, GRPC_JSON_ARRAY); reader->depth++; reader->in_object = 0; reader->in_array = 1; break; } break; case GRPC_JSON_STATE_STRING_ESCAPE: if (reader->escaped_string_was_key) { reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { reader->state = GRPC_JSON_STATE_VALUE_STRING; } if (reader->unicode_high_surrogate && c != 'u') return GRPC_JSON_PARSE_ERROR; switch (c) { case '"': case '/': json_reader_string_add_char(reader, c); break; case 'b': json_reader_string_add_char(reader, '\b'); break; case 'f': json_reader_string_add_char(reader, '\f'); break; case 'n': json_reader_string_add_char(reader, '\n'); break; case 'r': json_reader_string_add_char(reader, '\r'); break; case 't': json_reader_string_add_char(reader, '\t'); break; case 'u': reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1; reader->unicode_char = 0; break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_STRING_ESCAPE_U1: case GRPC_JSON_STATE_STRING_ESCAPE_U2: case GRPC_JSON_STATE_STRING_ESCAPE_U3: case GRPC_JSON_STATE_STRING_ESCAPE_U4: if ((c >= '0') && (c <= '9')) { c -= '0'; } else if ((c >= 'A') && (c <= 'F')) { c -= 'A' - 10; } else if ((c >= 'a') && (c <= 'f')) { c -= 'a' - 10; } else { return GRPC_JSON_PARSE_ERROR; } reader->unicode_char = (gpr_uint16)(reader->unicode_char << 4); reader->unicode_char = (gpr_uint16)(reader->unicode_char | c); switch (reader->state) { case GRPC_JSON_STATE_STRING_ESCAPE_U1: reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2; break; case GRPC_JSON_STATE_STRING_ESCAPE_U2: reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3; break; case GRPC_JSON_STATE_STRING_ESCAPE_U3: reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4; break; case GRPC_JSON_STATE_STRING_ESCAPE_U4: /* See grpc_json_writer_escape_string to have a description * of what's going on here. */ if ((reader->unicode_char & 0xfc00) == 0xd800) { /* high surrogate utf-16 */ if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; reader->unicode_high_surrogate = reader->unicode_char; } else if ((reader->unicode_char & 0xfc00) == 0xdc00) { /* low surrogate utf-16 */ gpr_uint32 utf32; if (reader->unicode_high_surrogate == 0) return GRPC_JSON_PARSE_ERROR; utf32 = 0x10000; utf32 += (gpr_uint32)( (reader->unicode_high_surrogate - 0xd800) * 0x400); utf32 += (gpr_uint32)(reader->unicode_char - 0xdc00); json_reader_string_add_utf32(reader, utf32); reader->unicode_high_surrogate = 0; } else { /* anything else */ if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; json_reader_string_add_utf32(reader, reader->unicode_char); } if (reader->escaped_string_was_key) { reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { reader->state = GRPC_JSON_STATE_VALUE_STRING; } break; default: return GRPC_JSON_INTERNAL_ERROR; } break; case GRPC_JSON_STATE_VALUE_NUMBER: json_reader_string_add_char(reader, c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case 'e': case 'E': reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; break; case '.': reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: json_reader_string_add_char(reader, c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case 'e': case 'E': reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: if (c != '.') return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; break; case GRPC_JSON_STATE_VALUE_NUMBER_DOT: json_reader_string_add_char(reader, c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_VALUE_NUMBER_E: json_reader_string_add_char(reader, c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM; break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_VALUE_NUMBER_EPM: json_reader_string_add_char(reader, c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_VALUE_TRUE_R: if (c != 'r') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_TRUE_U; break; case GRPC_JSON_STATE_VALUE_TRUE_U: if (c != 'u') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_TRUE_E; break; case GRPC_JSON_STATE_VALUE_TRUE_E: if (c != 'e') return GRPC_JSON_PARSE_ERROR; json_reader_set_true(reader); reader->state = GRPC_JSON_STATE_VALUE_END; break; case GRPC_JSON_STATE_VALUE_FALSE_A: if (c != 'a') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_FALSE_L; break; case GRPC_JSON_STATE_VALUE_FALSE_L: if (c != 'l') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_FALSE_S; break; case GRPC_JSON_STATE_VALUE_FALSE_S: if (c != 's') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_FALSE_E; break; case GRPC_JSON_STATE_VALUE_FALSE_E: if (c != 'e') return GRPC_JSON_PARSE_ERROR; json_reader_set_false(reader); reader->state = GRPC_JSON_STATE_VALUE_END; break; case GRPC_JSON_STATE_VALUE_NULL_U: if (c != 'u') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_NULL_L1; break; case GRPC_JSON_STATE_VALUE_NULL_L1: if (c != 'l') return GRPC_JSON_PARSE_ERROR; reader->state = GRPC_JSON_STATE_VALUE_NULL_L2; break; case GRPC_JSON_STATE_VALUE_NULL_L2: if (c != 'l') return GRPC_JSON_PARSE_ERROR; json_reader_set_null(reader); reader->state = GRPC_JSON_STATE_VALUE_END; break; /* All of the VALUE_END cases are handled in the specialized case * above. */ case GRPC_JSON_STATE_VALUE_END: switch (c) { case ',': case '}': case ']': return GRPC_JSON_INTERNAL_ERROR; break; default: return GRPC_JSON_PARSE_ERROR; } break; case GRPC_JSON_STATE_END: return GRPC_JSON_PARSE_ERROR; } } } return GRPC_JSON_INTERNAL_ERROR; } grpc-0.11.1/src/core/json/json_string.c0000644000175000017500000003035312600663151020116 0ustar apollockapollock/* * * 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 #include #include #include #include "src/core/json/json.h" #include "src/core/json/json_reader.h" #include "src/core/json/json_writer.h" /* The json reader will construct a bunch of grpc_json objects and * link them all up together in a tree-like structure that will represent * the json data in memory. * * It also uses its own input as a scratchpad to store all of the decoded, * unescaped strings. So we need to keep track of all these pointers in * that opaque structure the reader will carry for us. * * Note that this works because the act of parsing json always reduces its * input size, and never expands it. */ typedef struct { grpc_json* top; grpc_json* current_container; grpc_json* current_value; gpr_uint8* input; gpr_uint8* key; gpr_uint8* string; gpr_uint8* string_ptr; size_t remaining_input; } json_reader_userdata; /* This json writer will put everything in a big string. * The point is that we allocate that string in chunks of 256 bytes. */ typedef struct { char* output; size_t free_space; size_t string_len; size_t allocated; } json_writer_userdata; /* This function checks if there's enough space left in the output buffer, * and will enlarge it if necessary. We're only allocating chunks of 256 * bytes at a time (or multiples thereof). */ static void json_writer_output_check(void* userdata, size_t needed) { json_writer_userdata* state = userdata; if (state->free_space >= needed) return; needed -= state->free_space; /* Round up by 256 bytes. */ needed = (needed + 0xff) & ~0xffU; state->output = gpr_realloc(state->output, state->allocated + needed); state->free_space += needed; state->allocated += needed; } /* These are needed by the writer's implementation. */ static void json_writer_output_char(void* userdata, char c) { json_writer_userdata* state = userdata; json_writer_output_check(userdata, 1); state->output[state->string_len++] = c; state->free_space--; } static void json_writer_output_string_with_len(void* userdata, const char* str, size_t len) { json_writer_userdata* state = userdata; json_writer_output_check(userdata, len); memcpy(state->output + state->string_len, str, len); state->string_len += len; state->free_space -= len; } static void json_writer_output_string(void* userdata, const char* str) { size_t len = strlen(str); json_writer_output_string_with_len(userdata, str, len); } /* The reader asks us to clear our scratchpad. In our case, we'll simply mark * the end of the current string, and advance our output pointer. */ static void json_reader_string_clear(void* userdata) { json_reader_userdata* state = userdata; if (state->string) { GPR_ASSERT(state->string_ptr < state->input); *state->string_ptr++ = 0; } state->string = state->string_ptr; } static void json_reader_string_add_char(void* userdata, gpr_uint32 c) { json_reader_userdata* state = userdata; GPR_ASSERT(state->string_ptr < state->input); GPR_ASSERT(c <= 0xff); *state->string_ptr++ = (gpr_uint8)c; } /* We are converting a UTF-32 character into UTF-8 here, * as described by RFC3629. */ static void json_reader_string_add_utf32(void* userdata, gpr_uint32 c) { if (c <= 0x7f) { json_reader_string_add_char(userdata, c); } else if (c <= 0x7ff) { gpr_uint32 b1 = 0xc0 | ((c >> 6) & 0x1f); gpr_uint32 b2 = 0x80 | (c & 0x3f); json_reader_string_add_char(userdata, b1); json_reader_string_add_char(userdata, b2); } else if (c <= 0xffff) { gpr_uint32 b1 = 0xe0 | ((c >> 12) & 0x0f); gpr_uint32 b2 = 0x80 | ((c >> 6) & 0x3f); gpr_uint32 b3 = 0x80 | (c & 0x3f); json_reader_string_add_char(userdata, b1); json_reader_string_add_char(userdata, b2); json_reader_string_add_char(userdata, b3); } else if (c <= 0x1fffff) { gpr_uint32 b1 = 0xf0 | ((c >> 18) & 0x07); gpr_uint32 b2 = 0x80 | ((c >> 12) & 0x3f); gpr_uint32 b3 = 0x80 | ((c >> 6) & 0x3f); gpr_uint32 b4 = 0x80 | (c & 0x3f); json_reader_string_add_char(userdata, b1); json_reader_string_add_char(userdata, b2); json_reader_string_add_char(userdata, b3); json_reader_string_add_char(userdata, b4); } } /* We consider that the input may be a zero-terminated string. So we * can end up hitting eof before the end of the alleged string length. */ static gpr_uint32 json_reader_read_char(void* userdata) { gpr_uint32 r; json_reader_userdata* state = userdata; if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF; r = *state->input++; state->remaining_input--; if (r == 0) { state->remaining_input = 0; return GRPC_JSON_READ_CHAR_EOF; } return r; } /* Helper function to create a new grpc_json object and link it into * our tree-in-progress inside our opaque structure. */ static grpc_json* json_create_and_link(void* userdata, grpc_json_type type) { json_reader_userdata* state = userdata; grpc_json* json = grpc_json_create(type); json->parent = state->current_container; json->prev = state->current_value; state->current_value = json; if (json->prev) { json->prev->next = json; } if (json->parent) { if (!json->parent->child) { json->parent->child = json; } if (json->parent->type == GRPC_JSON_OBJECT) { json->key = (char*)state->key; } } if (!state->top) { state->top = json; } return json; } static void json_reader_container_begins(void* userdata, grpc_json_type type) { json_reader_userdata* state = userdata; grpc_json* container; GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT); container = json_create_and_link(userdata, type); state->current_container = container; state->current_value = NULL; } /* It's important to remember that the reader is mostly stateless, so it * isn't trying to remember what the container was prior the one that just * ends. Since we're keeping track of these for our own purpose, we are * able to return that information back, which is useful for it to validate * the input json stream. * * Also note that if we're at the top of the tree, and the last container * ends, we have to return GRPC_JSON_TOP_LEVEL. */ static grpc_json_type json_reader_container_ends(void* userdata) { grpc_json_type container_type = GRPC_JSON_TOP_LEVEL; json_reader_userdata* state = userdata; GPR_ASSERT(state->current_container); state->current_value = state->current_container; state->current_container = state->current_container->parent; if (state->current_container) { container_type = state->current_container->type; } return container_type; } /* The next 3 functions basically are the reader asking us to use our string * scratchpad for one of these 3 purposes. * * Note that in the set_number case, we're not going to try interpreting it. * We'll keep it as a string, and leave it to the caller to evaluate it. */ static void json_reader_set_key(void* userdata) { json_reader_userdata* state = userdata; state->key = state->string; } static void json_reader_set_string(void* userdata) { json_reader_userdata* state = userdata; grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING); json->value = (char*)state->string; } static int json_reader_set_number(void* userdata) { json_reader_userdata* state = userdata; grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER); json->value = (char*)state->string; return 1; } /* The object types true, false and null are self-sufficient, and don't need * any more information beside their type. */ static void json_reader_set_true(void* userdata) { json_create_and_link(userdata, GRPC_JSON_TRUE); } static void json_reader_set_false(void* userdata) { json_create_and_link(userdata, GRPC_JSON_FALSE); } static void json_reader_set_null(void* userdata) { json_create_and_link(userdata, GRPC_JSON_NULL); } static grpc_json_reader_vtable reader_vtable = { json_reader_string_clear, json_reader_string_add_char, json_reader_string_add_utf32, json_reader_read_char, json_reader_container_begins, json_reader_container_ends, json_reader_set_key, json_reader_set_string, json_reader_set_number, json_reader_set_true, json_reader_set_false, json_reader_set_null}; /* And finally, let's define our public API. */ grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) { grpc_json_reader reader; json_reader_userdata state; grpc_json* json = NULL; grpc_json_reader_status status; if (!input) return NULL; state.top = state.current_container = state.current_value = NULL; state.string = state.key = NULL; state.string_ptr = state.input = (gpr_uint8*)input; state.remaining_input = size; grpc_json_reader_init(&reader, &reader_vtable, &state); status = grpc_json_reader_run(&reader); json = state.top; if ((status != GRPC_JSON_DONE) && json) { grpc_json_destroy(json); json = NULL; } return json; } #define UNBOUND_JSON_STRING_LENGTH 0x7fffffff grpc_json* grpc_json_parse_string(char* input) { return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH); } static void json_dump_recursive(grpc_json_writer* writer, grpc_json* json, int in_object) { while (json) { if (in_object) grpc_json_writer_object_key(writer, json->key); switch (json->type) { case GRPC_JSON_OBJECT: case GRPC_JSON_ARRAY: grpc_json_writer_container_begins(writer, json->type); if (json->child) json_dump_recursive(writer, json->child, json->type == GRPC_JSON_OBJECT); grpc_json_writer_container_ends(writer, json->type); break; case GRPC_JSON_STRING: grpc_json_writer_value_string(writer, json->value); break; case GRPC_JSON_NUMBER: grpc_json_writer_value_raw(writer, json->value); break; case GRPC_JSON_TRUE: grpc_json_writer_value_raw_with_len(writer, "true", 4); break; case GRPC_JSON_FALSE: grpc_json_writer_value_raw_with_len(writer, "false", 5); break; case GRPC_JSON_NULL: grpc_json_writer_value_raw_with_len(writer, "null", 4); break; default: abort(); } json = json->next; } } static grpc_json_writer_vtable writer_vtable = { json_writer_output_char, json_writer_output_string, json_writer_output_string_with_len}; char* grpc_json_dump_to_string(grpc_json* json, int indent) { grpc_json_writer writer; json_writer_userdata state; state.output = NULL; state.free_space = state.string_len = state.allocated = 0; grpc_json_writer_init(&writer, indent, &writer_vtable, &state); json_dump_recursive(&writer, json, 0); json_writer_output_char(&state, 0); return state.output; } grpc-0.11.1/src/core/transport/0000755000175000017500000000000012600663151016472 5ustar apollockapollockgrpc-0.11.1/src/core/transport/transport.c0000644000175000017500000001160212600663151020672 0ustar apollockapollock/* * * 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/transport/transport.h" #include #include #include "src/core/transport/transport_impl.h" size_t grpc_transport_stream_size(grpc_transport *transport) { return transport->vtable->sizeof_stream; } void grpc_transport_destroy(grpc_transport *transport) { transport->vtable->destroy(transport); } int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, const void *server_data, grpc_transport_stream_op *initial_op) { return transport->vtable->init_stream(transport, stream, server_data, initial_op); } void grpc_transport_perform_stream_op(grpc_transport *transport, grpc_stream *stream, grpc_transport_stream_op *op) { transport->vtable->perform_stream_op(transport, stream, op); } void grpc_transport_perform_op(grpc_transport *transport, grpc_transport_op *op) { transport->vtable->perform_op(transport, op); } void grpc_transport_destroy_stream(grpc_transport *transport, grpc_stream *stream) { transport->vtable->destroy_stream(transport, stream); } char *grpc_transport_get_peer(grpc_transport *transport) { return transport->vtable->get_peer(transport); } void grpc_transport_stream_op_finish_with_failure( grpc_transport_stream_op *op) { if (op->send_ops) { op->on_done_send->cb(op->on_done_send->cb_arg, 0); } if (op->recv_ops) { op->on_done_recv->cb(op->on_done_recv->cb_arg, 0); } if (op->on_consumed) { op->on_consumed->cb(op->on_consumed->cb_arg, 0); } } void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, grpc_status_code status) { GPR_ASSERT(status != GRPC_STATUS_OK); if (op->cancel_with_status == GRPC_STATUS_OK) { op->cancel_with_status = status; } if (op->close_with_status != GRPC_STATUS_OK) { op->close_with_status = GRPC_STATUS_OK; if (op->optional_close_message != NULL) { gpr_slice_unref(*op->optional_close_message); op->optional_close_message = NULL; } } } typedef struct { gpr_slice message; grpc_iomgr_closure *then_call; grpc_iomgr_closure closure; } close_message_data; static void free_message(void *p, int iomgr_success) { close_message_data *cmd = p; gpr_slice_unref(cmd->message); if (cmd->then_call != NULL) { cmd->then_call->cb(cmd->then_call->cb_arg, iomgr_success); } gpr_free(cmd); } void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, grpc_status_code status, gpr_slice *optional_message) { close_message_data *cmd; GPR_ASSERT(status != GRPC_STATUS_OK); if (op->cancel_with_status != GRPC_STATUS_OK || op->close_with_status != GRPC_STATUS_OK) { if (optional_message) { gpr_slice_unref(*optional_message); } return; } if (optional_message) { cmd = gpr_malloc(sizeof(*cmd)); cmd->message = *optional_message; cmd->then_call = op->on_consumed; grpc_iomgr_closure_init(&cmd->closure, free_message, cmd); op->on_consumed = &cmd->closure; op->optional_close_message = &cmd->message; } op->close_with_status = status; } grpc-0.11.1/src/core/transport/metadata.c0000644000175000017500000005454712600663151020435 0ustar apollockapollock/* * * 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/iomgr/sockaddr.h" #include "src/core/transport/metadata.h" #include #include #include #include #include #include #include "src/core/support/murmur_hash.h" #include "src/core/transport/chttp2/bin_encoder.h" #include #define INITIAL_STRTAB_CAPACITY 4 #define INITIAL_MDTAB_CAPACITY 4 #ifdef GRPC_METADATA_REFCOUNT_DEBUG #define DEBUG_ARGS , const char *file, int line #define FWD_DEBUG_ARGS , file, line #define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__) #define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__) #define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__) #else #define DEBUG_ARGS #define FWD_DEBUG_ARGS #define INTERNAL_STRING_REF(s) internal_string_ref((s)) #define INTERNAL_STRING_UNREF(s) internal_string_unref((s)) #define REF_MD_LOCKED(s) ref_md_locked((s)) #endif typedef struct internal_string { /* must be byte compatible with grpc_mdstr */ gpr_slice slice; gpr_uint32 hash; /* private only data */ gpr_uint32 refs; gpr_uint8 has_base64_and_huffman_encoded; gpr_slice_refcount refcount; gpr_slice base64_and_huffman; grpc_mdctx *context; struct internal_string *bucket_next; } internal_string; typedef struct internal_metadata { /* must be byte compatible with grpc_mdelem */ internal_string *key; internal_string *value; gpr_atm refcnt; /* private only data */ gpr_mu mu_user_data; void *user_data; void (*destroy_user_data)(void *user_data); grpc_mdctx *context; struct internal_metadata *bucket_next; } internal_metadata; struct grpc_mdctx { gpr_uint32 hash_seed; int refs; gpr_mu mu; internal_string **strtab; size_t strtab_count; size_t strtab_capacity; internal_metadata **mdtab; size_t mdtab_count; size_t mdtab_free; size_t mdtab_capacity; }; static void internal_string_ref(internal_string *s DEBUG_ARGS); static void internal_string_unref(internal_string *s DEBUG_ARGS); static void discard_metadata(grpc_mdctx *ctx); static void gc_mdtab(grpc_mdctx *ctx); static void metadata_context_destroy_locked(grpc_mdctx *ctx); static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); } static void unlock(grpc_mdctx *ctx) { /* If the context has been orphaned we'd like to delete it soon. We check conditions in unlock as it signals the end of mutations on a context. We need to ensure all grpc_mdelem and grpc_mdstr elements have been deleted first. This is equivalent to saying that both tables have zero counts, which is equivalent to saying that strtab_count is zero (as mdelem's MUST reference an mdstr for their key and value slots). To encourage that to happen, we start discarding zero reference count mdelems on every unlock (instead of the usual 'I'm too loaded' trigger case), since otherwise we can be stuck waiting for a garbage collection that will never happen. */ if (ctx->refs == 0) { /* uncomment if you're having trouble diagnosing an mdelem leak to make things clearer (slows down destruction a lot, however) */ #ifdef GRPC_METADATA_REFCOUNT_DEBUG gc_mdtab(ctx); #endif if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) { discard_metadata(ctx); } if (ctx->strtab_count == 0) { metadata_context_destroy_locked(ctx); return; } } gpr_mu_unlock(&ctx->mu); } static void ref_md_locked(internal_metadata *md DEBUG_ARGS) { #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "ELM REF:%p:%d->%d: '%s' = '%s'", md, gpr_atm_no_barrier_load(&md->refcnt), gpr_atm_no_barrier_load(&md->refcnt) + 1, grpc_mdstr_as_c_string((grpc_mdstr *)md->key), grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); #endif if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) { md->context->mdtab_free--; } } grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) { grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx)); ctx->refs = 1; ctx->hash_seed = seed; gpr_mu_init(&ctx->mu); ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY); memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY); ctx->strtab_count = 0; ctx->strtab_capacity = INITIAL_STRTAB_CAPACITY; ctx->mdtab = gpr_malloc(sizeof(internal_metadata *) * INITIAL_MDTAB_CAPACITY); memset(ctx->mdtab, 0, sizeof(grpc_mdelem *) * INITIAL_MDTAB_CAPACITY); ctx->mdtab_count = 0; ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY; ctx->mdtab_free = 0; return ctx; } grpc_mdctx *grpc_mdctx_create(void) { /* This seed is used to prevent remote connections from controlling hash table * collisions. It needs to be somewhat unpredictable to a remote connection. */ return grpc_mdctx_create_with_seed(gpr_now(GPR_CLOCK_REALTIME).tv_nsec); } static void discard_metadata(grpc_mdctx *ctx) { size_t i; internal_metadata *next, *cur; for (i = 0; i < ctx->mdtab_capacity; i++) { cur = ctx->mdtab[i]; while (cur) { GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0); next = cur->bucket_next; INTERNAL_STRING_UNREF(cur->key); INTERNAL_STRING_UNREF(cur->value); if (cur->user_data) { cur->destroy_user_data(cur->user_data); } gpr_mu_destroy(&cur->mu_user_data); gpr_free(cur); cur = next; ctx->mdtab_free--; ctx->mdtab_count--; } ctx->mdtab[i] = NULL; } } static void metadata_context_destroy_locked(grpc_mdctx *ctx) { GPR_ASSERT(ctx->strtab_count == 0); GPR_ASSERT(ctx->mdtab_count == 0); GPR_ASSERT(ctx->mdtab_free == 0); gpr_free(ctx->strtab); gpr_free(ctx->mdtab); gpr_mu_unlock(&ctx->mu); gpr_mu_destroy(&ctx->mu); gpr_free(ctx); } void grpc_mdctx_ref(grpc_mdctx *ctx) { lock(ctx); GPR_ASSERT(ctx->refs > 0); ctx->refs++; unlock(ctx); } void grpc_mdctx_unref(grpc_mdctx *ctx) { lock(ctx); GPR_ASSERT(ctx->refs > 0); ctx->refs--; unlock(ctx); } static void grow_strtab(grpc_mdctx *ctx) { size_t capacity = ctx->strtab_capacity * 2; size_t i; internal_string **strtab = gpr_malloc(sizeof(internal_string *) * capacity); internal_string *s, *next; memset(strtab, 0, sizeof(internal_string *) * capacity); for (i = 0; i < ctx->strtab_capacity; i++) { for (s = ctx->strtab[i]; s; s = next) { next = s->bucket_next; s->bucket_next = strtab[s->hash % capacity]; strtab[s->hash % capacity] = s; } } gpr_free(ctx->strtab); ctx->strtab = strtab; ctx->strtab_capacity = capacity; } static void internal_destroy_string(internal_string *is) { internal_string **prev_next; internal_string *cur; grpc_mdctx *ctx = is->context; if (is->has_base64_and_huffman_encoded) { gpr_slice_unref(is->base64_and_huffman); } for (prev_next = &ctx->strtab[is->hash % ctx->strtab_capacity], cur = *prev_next; cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next) ; *prev_next = cur->bucket_next; ctx->strtab_count--; gpr_free(is); } static void internal_string_ref(internal_string *s DEBUG_ARGS) { #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%d->%d: '%s'", s, s->refs, s->refs + 1, grpc_mdstr_as_c_string((grpc_mdstr *)s)); #endif ++s->refs; } static void internal_string_unref(internal_string *s DEBUG_ARGS) { #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%d->%d: '%s'", s, s->refs, s->refs - 1, grpc_mdstr_as_c_string((grpc_mdstr *)s)); #endif GPR_ASSERT(s->refs > 0); if (0 == --s->refs) { internal_destroy_string(s); } } static void slice_ref(void *p) { internal_string *is = (internal_string *)((char *)p - offsetof(internal_string, refcount)); grpc_mdctx *ctx = is->context; lock(ctx); INTERNAL_STRING_REF(is); unlock(ctx); } static void slice_unref(void *p) { internal_string *is = (internal_string *)((char *)p - offsetof(internal_string, refcount)); grpc_mdctx *ctx = is->context; lock(ctx); INTERNAL_STRING_UNREF(is); unlock(ctx); } grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int canonicalize_key) { if (canonicalize_key) { size_t len; size_t i; int canonical = 1; for (i = 0; str[i]; i++) { if (str[i] >= 'A' && str[i] <= 'Z') { canonical = 0; /* Keep going in loop just to get string length */ } } len = i; if (canonical) { return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, len); } else { char *copy = gpr_malloc(len); grpc_mdstr *ret; for (i = 0; i < len; i++) { if (str[i] >= 'A' && str[i] <= 'Z') { copy[i] = str[i] - 'A' + 'a'; } else { copy[i] = str[i]; } } ret = grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)copy, len); gpr_free(copy); return ret; } } return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str)); } grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice) { grpc_mdstr *result = grpc_mdstr_from_buffer(ctx, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)); gpr_slice_unref(slice); return result; } grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf, size_t length) { gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed); internal_string *s; lock(ctx); /* search for an existing string */ for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) { if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length && 0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) { INTERNAL_STRING_REF(s); unlock(ctx); return (grpc_mdstr *)s; } } /* not found: create a new string */ if (length + 1 < GPR_SLICE_INLINED_SIZE) { /* string data goes directly into the slice */ s = gpr_malloc(sizeof(internal_string)); s->refs = 1; s->slice.refcount = NULL; memcpy(s->slice.data.inlined.bytes, buf, length); s->slice.data.inlined.bytes[length] = 0; s->slice.data.inlined.length = length; } else { /* string data goes after the internal_string header, and we +1 for null terminator */ s = gpr_malloc(sizeof(internal_string) + length + 1); s->refs = 1; s->refcount.ref = slice_ref; s->refcount.unref = slice_unref; s->slice.refcount = &s->refcount; s->slice.data.refcounted.bytes = (gpr_uint8 *)(s + 1); s->slice.data.refcounted.length = length; memcpy(s->slice.data.refcounted.bytes, buf, length); /* add a null terminator for cheap c string conversion when desired */ s->slice.data.refcounted.bytes[length] = 0; } s->has_base64_and_huffman_encoded = 0; s->hash = hash; s->context = ctx; s->bucket_next = ctx->strtab[hash % ctx->strtab_capacity]; ctx->strtab[hash % ctx->strtab_capacity] = s; ctx->strtab_count++; if (ctx->strtab_count > ctx->strtab_capacity * 2) { grow_strtab(ctx); } unlock(ctx); return (grpc_mdstr *)s; } static void gc_mdtab(grpc_mdctx *ctx) { size_t i; internal_metadata **prev_next; internal_metadata *md, *next; for (i = 0; i < ctx->mdtab_capacity; i++) { prev_next = &ctx->mdtab[i]; for (md = ctx->mdtab[i]; md; md = next) { next = md->bucket_next; if (gpr_atm_acq_load(&md->refcnt) == 0) { INTERNAL_STRING_UNREF(md->key); INTERNAL_STRING_UNREF(md->value); if (md->user_data) { md->destroy_user_data(md->user_data); } gpr_free(md); *prev_next = next; ctx->mdtab_free--; ctx->mdtab_count--; } else { prev_next = &md->bucket_next; } } } GPR_ASSERT(ctx->mdtab_free == 0); } static void grow_mdtab(grpc_mdctx *ctx) { size_t capacity = ctx->mdtab_capacity * 2; size_t i; internal_metadata **mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity); internal_metadata *md, *next; gpr_uint32 hash; memset(mdtab, 0, sizeof(internal_metadata *) * capacity); for (i = 0; i < ctx->mdtab_capacity; i++) { for (md = ctx->mdtab[i]; md; md = next) { hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); next = md->bucket_next; md->bucket_next = mdtab[hash % capacity]; mdtab[hash % capacity] = md; } } gpr_free(ctx->mdtab); ctx->mdtab = mdtab; ctx->mdtab_capacity = capacity; } static void rehash_mdtab(grpc_mdctx *ctx) { if (ctx->mdtab_free > ctx->mdtab_capacity / 4) { gc_mdtab(ctx); } else { grow_mdtab(ctx); } } grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdstr *mkey, grpc_mdstr *mvalue) { internal_string *key = (internal_string *)mkey; internal_string *value = (internal_string *)mvalue; gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash); internal_metadata *md; GPR_ASSERT(key->context == ctx); GPR_ASSERT(value->context == ctx); lock(ctx); /* search for an existing pair */ for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) { if (md->key == key && md->value == value) { REF_MD_LOCKED(md); INTERNAL_STRING_UNREF(key); INTERNAL_STRING_UNREF(value); unlock(ctx); return (grpc_mdelem *)md; } } /* not found: create a new pair */ md = gpr_malloc(sizeof(internal_metadata)); gpr_atm_rel_store(&md->refcnt, 1); md->context = ctx; md->key = key; md->value = value; md->user_data = NULL; md->destroy_user_data = NULL; md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity]; gpr_mu_init(&md->mu_user_data); #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md, gpr_atm_no_barrier_load(&md->refcnt), grpc_mdstr_as_c_string((grpc_mdstr *)md->key), grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); #endif ctx->mdtab[hash % ctx->mdtab_capacity] = md; ctx->mdtab_count++; if (ctx->mdtab_count > ctx->mdtab_capacity * 2) { rehash_mdtab(ctx); } unlock(ctx); return (grpc_mdelem *)md; } grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key, const char *value) { return grpc_mdelem_from_metadata_strings( ctx, grpc_mdstr_from_string(ctx, key, 0), grpc_mdstr_from_string(ctx, value, 0)); } grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, gpr_slice value) { return grpc_mdelem_from_metadata_strings(ctx, grpc_mdstr_from_slice(ctx, key), grpc_mdstr_from_slice(ctx, value)); } grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx, const char *key, const gpr_uint8 *value, size_t value_length, int canonicalize_key) { return grpc_mdelem_from_metadata_strings( ctx, grpc_mdstr_from_string(ctx, key, canonicalize_key), grpc_mdstr_from_buffer(ctx, value, value_length)); } grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) { internal_metadata *md = (internal_metadata *)gmd; #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "ELM REF:%p:%d->%d: '%s' = '%s'", md, gpr_atm_no_barrier_load(&md->refcnt), gpr_atm_no_barrier_load(&md->refcnt) + 1, grpc_mdstr_as_c_string((grpc_mdstr *)md->key), grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); #endif /* we can assume the ref count is >= 1 as the application is calling this function - meaning that no adjustment to mdtab_free is necessary, simplifying the logic here to be just an atomic increment */ /* use C assert to have this removed in opt builds */ assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1); gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); return gmd; } void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) { internal_metadata *md = (internal_metadata *)gmd; grpc_mdctx *ctx = md->context; lock(ctx); #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "ELM UNREF:%p:%d->%d: '%s' = '%s'", md, gpr_atm_no_barrier_load(&md->refcnt), gpr_atm_no_barrier_load(&md->refcnt) - 1, grpc_mdstr_as_c_string((grpc_mdstr *)md->key), grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); #endif assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1); if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) { ctx->mdtab_free++; } unlock(ctx); } const char *grpc_mdstr_as_c_string(grpc_mdstr *s) { return (const char *)GPR_SLICE_START_PTR(s->slice); } grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) { internal_string *s = (internal_string *)gs; grpc_mdctx *ctx = s->context; lock(ctx); internal_string_ref(s FWD_DEBUG_ARGS); unlock(ctx); return gs; } void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) { internal_string *s = (internal_string *)gs; grpc_mdctx *ctx = s->context; lock(ctx); internal_string_unref(s FWD_DEBUG_ARGS); unlock(ctx); } size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *ctx) { return ctx->mdtab_capacity; } size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *ctx) { return ctx->mdtab_count; } size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) { return ctx->mdtab_free; } void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*if_destroy_func)(void *)) { internal_metadata *im = (internal_metadata *)md; void *result; gpr_mu_lock(&im->mu_user_data); result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL; gpr_mu_unlock(&im->mu_user_data); return result; } void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), void *user_data) { internal_metadata *im = (internal_metadata *)md; GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); gpr_mu_lock(&im->mu_user_data); if (im->destroy_user_data) { /* user data can only be set once */ gpr_mu_unlock(&im->mu_user_data); if (destroy_func != NULL) { destroy_func(user_data); } return; } im->destroy_user_data = destroy_func; im->user_data = user_data; gpr_mu_unlock(&im->mu_user_data); } gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) { internal_string *s = (internal_string *)gs; gpr_slice slice; grpc_mdctx *ctx = s->context; lock(ctx); if (!s->has_base64_and_huffman_encoded) { s->base64_and_huffman = grpc_chttp2_base64_encode_and_huffman_compress(s->slice); s->has_base64_and_huffman_encoded = 1; } slice = s->base64_and_huffman; unlock(ctx); return slice; } void grpc_mdctx_lock(grpc_mdctx *ctx) { lock(ctx); } void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *gmd DEBUG_ARGS) { internal_metadata *md = (internal_metadata *)gmd; grpc_mdctx *elem_ctx = md->context; GPR_ASSERT(ctx == elem_ctx); #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "ELM UNREF:%p:%d->%d: '%s' = '%s'", md, gpr_atm_no_barrier_load(&md->refcnt), gpr_atm_no_barrier_load(&md->refcnt) - 1, grpc_mdstr_as_c_string((grpc_mdstr *)md->key), grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); #endif assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1); if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) { ctx->mdtab_free++; } } void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); } static int conforms_to(grpc_mdstr *s, const gpr_uint8 *legal_bits) { const gpr_uint8 *p = GPR_SLICE_START_PTR(s->slice); const gpr_uint8 *e = GPR_SLICE_END_PTR(s->slice); for (; p != e; p++) { int idx = *p; int byte = idx / 8; int bit = idx % 8; if ((legal_bits[byte] & (1 << bit)) == 0) return 0; } return 1; } int grpc_mdstr_is_legal_header(grpc_mdstr *s) { static const gpr_uint8 legal_header_bits[256 / 8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00, 0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; return conforms_to(s, legal_header_bits); } int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) { static const gpr_uint8 legal_header_bits[256 / 8] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; return conforms_to(s, legal_header_bits); } int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s) { /* TODO(ctiller): consider caching this */ return grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(s->slice), GPR_SLICE_LENGTH(s->slice)); } grpc-0.11.1/src/core/transport/transport_op_string.c0000644000175000017500000001245412600663151022764 0ustar apollockapollock/* * * 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/channel/channel_stack.h" #include #include #include #include "src/core/support/string.h" #include #include #include /* These routines are here to facilitate debugging - they produce string representations of various transport data structures */ static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { gpr_strvec_add(b, gpr_strdup("key=")); gpr_strvec_add(b, gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); gpr_strvec_add(b, gpr_strdup(" value=")); gpr_strvec_add( b, gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); } static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { grpc_linked_mdelem *m; for (m = md.list.head; m != NULL; m = m->next) { if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", ")); put_metadata(b, m->md); } if (gpr_time_cmp(md.deadline, gpr_inf_future(md.deadline.clock_type)) != 0) { char *tmp; gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec, md.deadline.tv_nsec); gpr_strvec_add(b, tmp); } } char *grpc_sopb_string(grpc_stream_op_buffer *sopb) { char *out; char *tmp; size_t i; gpr_strvec b; gpr_strvec_init(&b); for (i = 0; i < sopb->nops; i++) { grpc_stream_op *op = &sopb->ops[i]; if (i > 0) gpr_strvec_add(&b, gpr_strdup(", ")); switch (op->type) { case GRPC_NO_OP: gpr_strvec_add(&b, gpr_strdup("NO_OP")); break; case GRPC_OP_BEGIN_MESSAGE: gpr_asprintf(&tmp, "BEGIN_MESSAGE:%d", op->data.begin_message.length); gpr_strvec_add(&b, tmp); break; case GRPC_OP_SLICE: gpr_asprintf(&tmp, "SLICE:%d", GPR_SLICE_LENGTH(op->data.slice)); gpr_strvec_add(&b, tmp); break; case GRPC_OP_METADATA: gpr_strvec_add(&b, gpr_strdup("METADATA{")); put_metadata_list(&b, op->data.metadata); gpr_strvec_add(&b, gpr_strdup("}")); break; } } out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); return out; } char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { char *tmp; char *out; int first = 1; gpr_strvec b; gpr_strvec_init(&b); if (op->send_ops) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; gpr_asprintf(&tmp, "SEND%s:%p", op->is_last_send ? "_LAST" : "", op->on_done_send); gpr_strvec_add(&b, tmp); gpr_strvec_add(&b, gpr_strdup("[")); gpr_strvec_add(&b, grpc_sopb_string(op->send_ops)); gpr_strvec_add(&b, gpr_strdup("]")); } if (op->recv_ops) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; gpr_asprintf(&tmp, "RECV:%p:max_recv_bytes=%d", op->on_done_recv, op->max_recv_bytes); gpr_strvec_add(&b, tmp); } if (op->bind_pollset) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; gpr_strvec_add(&b, gpr_strdup("BIND")); } if (op->cancel_with_status != GRPC_STATUS_OK) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status); gpr_strvec_add(&b, tmp); } if (op->on_consumed != NULL) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; gpr_asprintf(&tmp, "ON_CONSUMED:%p", op->on_consumed); gpr_strvec_add(&b, tmp); } out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); return out; } void grpc_call_log_op(char *file, int line, gpr_log_severity severity, grpc_call_element *elem, grpc_transport_stream_op *op) { char *str = grpc_transport_stream_op_string(op); gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); gpr_free(str); } grpc-0.11.1/src/core/transport/chttp2_transport.h0000644000175000017500000000421512600663151022165 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H #include "src/core/iomgr/endpoint.h" #include "src/core/transport/transport.h" extern int grpc_http_trace; extern int grpc_flowctl_trace; grpc_transport *grpc_create_chttp2_transport( const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *metadata_context, int is_client); void grpc_chttp2_transport_start_reading(grpc_transport *transport, gpr_slice *slices, size_t nslices); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H */ grpc-0.11.1/src/core/transport/stream_op.c0000644000175000017500000002423212600663151020632 0ustar apollockapollock/* * * 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/transport/stream_op.h" #include #include #include /* Exponential growth function: Given x, return a larger x. Currently we grow by 1.5 times upon reallocation. */ #define GROW(x) (3 * (x) / 2) void grpc_sopb_init(grpc_stream_op_buffer *sopb) { sopb->ops = sopb->inlined_ops; sopb->nops = 0; sopb->capacity = GRPC_SOPB_INLINE_ELEMENTS; } void grpc_sopb_destroy(grpc_stream_op_buffer *sopb) { grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops); if (sopb->ops != sopb->inlined_ops) gpr_free(sopb->ops); } void grpc_sopb_reset(grpc_stream_op_buffer *sopb) { grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops); sopb->nops = 0; } void grpc_sopb_swap(grpc_stream_op_buffer *a, grpc_stream_op_buffer *b) { GPR_SWAP(size_t, a->nops, b->nops); GPR_SWAP(size_t, a->capacity, b->capacity); if (a->ops == a->inlined_ops) { if (b->ops == b->inlined_ops) { /* swap contents of inlined buffer */ grpc_stream_op temp[GRPC_SOPB_INLINE_ELEMENTS]; memcpy(temp, a->ops, b->nops * sizeof(grpc_stream_op)); memcpy(a->ops, b->ops, a->nops * sizeof(grpc_stream_op)); memcpy(b->ops, temp, b->nops * sizeof(grpc_stream_op)); } else { /* a is inlined, b is not - copy a inlined into b, fix pointers */ a->ops = b->ops; b->ops = b->inlined_ops; memcpy(b->ops, a->inlined_ops, b->nops * sizeof(grpc_stream_op)); } } else if (b->ops == b->inlined_ops) { /* b is inlined, a is not - copy b inlined int a, fix pointers */ b->ops = a->ops; a->ops = a->inlined_ops; memcpy(a->ops, b->inlined_ops, a->nops * sizeof(grpc_stream_op)); } else { /* no inlining: easy swap */ GPR_SWAP(grpc_stream_op *, a->ops, b->ops); } } void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) { size_t i; for (i = 0; i < nops; i++) { switch (ops[i].type) { case GRPC_OP_SLICE: gpr_slice_unref(ops[i].data.slice); break; case GRPC_OP_METADATA: grpc_metadata_batch_destroy(&ops[i].data.metadata); break; case GRPC_NO_OP: case GRPC_OP_BEGIN_MESSAGE: break; } } } static void expandto(grpc_stream_op_buffer *sopb, size_t new_capacity) { sopb->capacity = new_capacity; if (sopb->ops == sopb->inlined_ops) { sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * new_capacity); memcpy(sopb->ops, sopb->inlined_ops, sopb->nops * sizeof(grpc_stream_op)); } else { sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity); } } static grpc_stream_op *add(grpc_stream_op_buffer *sopb) { grpc_stream_op *out; GPR_ASSERT(sopb->nops <= sopb->capacity); if (sopb->nops == sopb->capacity) { expandto(sopb, GROW(sopb->capacity)); } out = sopb->ops + sopb->nops; sopb->nops++; return out; } void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb) { add(sopb)->type = GRPC_NO_OP; } void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, gpr_uint32 flags) { grpc_stream_op *op = add(sopb); op->type = GRPC_OP_BEGIN_MESSAGE; op->data.begin_message.length = length; op->data.begin_message.flags = flags; } void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch b) { grpc_stream_op *op = add(sopb); op->type = GRPC_OP_METADATA; op->data.metadata = b; } void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) { grpc_stream_op *op = add(sopb); op->type = GRPC_OP_SLICE; op->data.slice = slice; } void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t nops) { size_t orig_nops = sopb->nops; size_t new_nops = orig_nops + nops; if (new_nops > sopb->capacity) { expandto(sopb, GPR_MAX(GROW(sopb->capacity), new_nops)); } memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops); sopb->nops = new_nops; } void grpc_sopb_move_to(grpc_stream_op_buffer *src, grpc_stream_op_buffer *dst) { if (src->nops == 0) { return; } if (dst->nops == 0) { grpc_sopb_swap(src, dst); return; } grpc_sopb_append(dst, src->ops, src->nops); src->nops = 0; } static void assert_valid_list(grpc_mdelem_list *list) { #ifndef NDEBUG grpc_linked_mdelem *l; GPR_ASSERT((list->head == NULL) == (list->tail == NULL)); if (!list->head) return; GPR_ASSERT(list->head->prev == NULL); GPR_ASSERT(list->tail->next == NULL); GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL)); for (l = list->head; l; l = l->next) { GPR_ASSERT(l->md); GPR_ASSERT((l->prev == NULL) == (l == list->head)); GPR_ASSERT((l->next == NULL) == (l == list->tail)); if (l->next) GPR_ASSERT(l->next->prev == l); if (l->prev) GPR_ASSERT(l->prev->next == l); } #endif /* NDEBUG */ } #ifndef NDEBUG void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) { assert_valid_list(&batch->list); assert_valid_list(&batch->garbage); } #endif /* NDEBUG */ void grpc_metadata_batch_init(grpc_metadata_batch *batch) { batch->list.head = batch->list.tail = batch->garbage.head = batch->garbage.tail = NULL; batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) { grpc_linked_mdelem *l; for (l = batch->list.head; l; l = l->next) { GRPC_MDELEM_UNREF(l->md); } for (l = batch->garbage.head; l; l = l->next) { GRPC_MDELEM_UNREF(l->md); } } void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, grpc_linked_mdelem *storage, grpc_mdelem *elem_to_add) { GPR_ASSERT(elem_to_add); storage->md = elem_to_add; grpc_metadata_batch_link_head(batch, storage); } static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { assert_valid_list(list); GPR_ASSERT(storage->md); storage->prev = NULL; storage->next = list->head; if (list->head != NULL) { list->head->prev = storage; } else { list->tail = storage; } list->head = storage; assert_valid_list(list); } void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, grpc_linked_mdelem *storage) { link_head(&batch->list, storage); } void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, grpc_linked_mdelem *storage, grpc_mdelem *elem_to_add) { GPR_ASSERT(elem_to_add); storage->md = elem_to_add; grpc_metadata_batch_link_tail(batch, storage); } static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { assert_valid_list(list); GPR_ASSERT(storage->md); storage->prev = list->tail; storage->next = NULL; storage->reserved = NULL; if (list->tail != NULL) { list->tail->next = storage; } else { list->head = storage; } list->tail = storage; assert_valid_list(list); } void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, grpc_linked_mdelem *storage) { link_tail(&batch->list, storage); } void grpc_metadata_batch_merge(grpc_metadata_batch *target, grpc_metadata_batch *add) { grpc_linked_mdelem *l; grpc_linked_mdelem *next; for (l = add->list.head; l; l = next) { next = l->next; link_tail(&target->list, l); } for (l = add->garbage.head; l; l = next) { next = l->next; link_tail(&target->garbage, l); } } void grpc_metadata_batch_move(grpc_metadata_batch *dst, grpc_metadata_batch *src) { *dst = *src; memset(src, 0, sizeof(grpc_metadata_batch)); } void grpc_metadata_batch_filter(grpc_metadata_batch *batch, grpc_mdelem *(*filter)(void *user_data, grpc_mdelem *elem), void *user_data) { grpc_linked_mdelem *l; grpc_linked_mdelem *next; assert_valid_list(&batch->list); assert_valid_list(&batch->garbage); for (l = batch->list.head; l; l = next) { grpc_mdelem *orig = l->md; grpc_mdelem *filt = filter(user_data, orig); next = l->next; if (filt == NULL) { if (l->prev) { l->prev->next = l->next; } if (l->next) { l->next->prev = l->prev; } if (batch->list.head == l) { batch->list.head = l->next; } if (batch->list.tail == l) { batch->list.tail = l->prev; } assert_valid_list(&batch->list); link_head(&batch->garbage, l); } else if (filt != orig) { GRPC_MDELEM_UNREF(orig); l->md = filt; } } assert_valid_list(&batch->list); assert_valid_list(&batch->garbage); } grpc-0.11.1/src/core/transport/stream_op.h0000644000175000017500000002113212600663151020633 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H #define GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H #include #include #include #include #include "src/core/transport/metadata.h" /* this many stream ops are inlined into a sopb before allocating */ #define GRPC_SOPB_INLINE_ELEMENTS 4 /* Operations that can be performed on a stream. Used by grpc_stream_op. */ typedef enum grpc_stream_op_code { /* Do nothing code. Useful if rewriting a batch to exclude some operations. Must be ignored by receivers */ GRPC_NO_OP, GRPC_OP_METADATA, /* Begin a message/metadata element/status - as defined by grpc_message_type. */ GRPC_OP_BEGIN_MESSAGE, /* Add a slice of data to the current message/metadata element/status. Must not overflow the forward declared length. */ GRPC_OP_SLICE } grpc_stream_op_code; /** Internal bit flag for grpc_begin_message's \a flags signaling the use of * compression for the message */ #define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u) /** Mask of all valid internal flags. */ #define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) /* Arguments for GRPC_OP_BEGIN_MESSAGE */ typedef struct grpc_begin_message { /* How many bytes of data will this message contain */ gpr_uint32 length; /* Write flags for the message: see grpc.h GRPC_WRITE_* for the public bits, * GRPC_WRITE_INTERNAL_* for the internal ones. */ gpr_uint32 flags; } grpc_begin_message; typedef struct grpc_linked_mdelem { grpc_mdelem *md; struct grpc_linked_mdelem *next; struct grpc_linked_mdelem *prev; void *reserved; } grpc_linked_mdelem; typedef struct grpc_mdelem_list { grpc_linked_mdelem *head; grpc_linked_mdelem *tail; } grpc_mdelem_list; typedef struct grpc_metadata_batch { /** Metadata elements in this batch */ grpc_mdelem_list list; /** Elements that have been removed from the batch, but have not yet been unreffed - used to allow collecting garbage under a single metadata context lock */ grpc_mdelem_list garbage; /** Used to calculate grpc-timeout at the point of sending, or gpr_inf_future if this batch does not need to send a grpc-timeout */ gpr_timespec deadline; } grpc_metadata_batch; void grpc_metadata_batch_init(grpc_metadata_batch *batch); void grpc_metadata_batch_destroy(grpc_metadata_batch *batch); void grpc_metadata_batch_merge(grpc_metadata_batch *target, grpc_metadata_batch *add); /** Moves the metadata information from \a src to \a dst. Upon return, \a src is * zeroed. */ void grpc_metadata_batch_move(grpc_metadata_batch *dst, grpc_metadata_batch *src); /** Add \a storage to the beginning of \a batch. storage->md is assumed to be valid. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. */ void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, grpc_linked_mdelem *storage); /** Add \a storage to the end of \a batch. storage->md is assumed to be valid. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. */ void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, grpc_linked_mdelem *storage); /** Add \a elem_to_add as the first element in \a batch, using \a storage as backing storage for the linked list element. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. Takes ownership of \a elem_to_add */ void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, grpc_linked_mdelem *storage, grpc_mdelem *elem_to_add); /** Add \a elem_to_add as the last element in \a batch, using \a storage as backing storage for the linked list element. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. Takes ownership of \a elem_to_add */ void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, grpc_linked_mdelem *storage, grpc_mdelem *elem_to_add); /** For each element in \a batch, execute \a filter. The return value from \a filter will be substituted for the grpc_mdelem passed to \a filter. If \a filter returns NULL, the element will be moved to the garbage list. */ void grpc_metadata_batch_filter(grpc_metadata_batch *batch, grpc_mdelem *(*filter)(void *user_data, grpc_mdelem *elem), void *user_data); #ifndef NDEBUG void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd); #else #define grpc_metadata_batch_assert_ok(comd) \ do { \ } while (0) #endif /* Represents a single operation performed on a stream/transport */ typedef struct grpc_stream_op { /* the operation to be applied */ enum grpc_stream_op_code type; /* the arguments to this operation. union fields are named according to the associated op-code */ union { grpc_begin_message begin_message; grpc_metadata_batch metadata; gpr_slice slice; } data; } grpc_stream_op; /** A stream op buffer is a wrapper around stream operations that is * dynamically extendable. */ typedef struct grpc_stream_op_buffer { grpc_stream_op *ops; size_t nops; size_t capacity; grpc_stream_op inlined_ops[GRPC_SOPB_INLINE_ELEMENTS]; } grpc_stream_op_buffer; /* Initialize a stream op buffer */ void grpc_sopb_init(grpc_stream_op_buffer *sopb); /* Destroy a stream op buffer */ void grpc_sopb_destroy(grpc_stream_op_buffer *sopb); /* Reset a sopb to no elements */ void grpc_sopb_reset(grpc_stream_op_buffer *sopb); /* Swap two sopbs */ void grpc_sopb_swap(grpc_stream_op_buffer *a, grpc_stream_op_buffer *b); void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops); /* Append a GRPC_NO_OP to a buffer */ void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb); /* Append a GRPC_OP_BEGIN to a buffer */ void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, gpr_uint32 flags); void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch metadata); /* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */ void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice); /* Append a buffer to a buffer - does not ref/unref any internal objects */ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t nops); void grpc_sopb_move_to(grpc_stream_op_buffer *src, grpc_stream_op_buffer *dst); char *grpc_sopb_string(grpc_stream_op_buffer *sopb); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */ grpc-0.11.1/src/core/transport/transport_impl.h0000644000175000017500000000574512600663151021733 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H #define GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H #include "src/core/transport/transport.h" typedef struct grpc_transport_vtable { /* Memory required for a single stream element - this is allocated by upper layers and initialized by the transport */ size_t sizeof_stream; /* = sizeof(transport stream) */ /* implementation of grpc_transport_init_stream */ int (*init_stream)(grpc_transport *self, grpc_stream *stream, const void *server_data, grpc_transport_stream_op *initial_op); /* implementation of grpc_transport_perform_stream_op */ void (*perform_stream_op)(grpc_transport *self, grpc_stream *stream, grpc_transport_stream_op *op); /* implementation of grpc_transport_perform_op */ void (*perform_op)(grpc_transport *self, grpc_transport_op *op); /* implementation of grpc_transport_destroy_stream */ void (*destroy_stream)(grpc_transport *self, grpc_stream *stream); /* implementation of grpc_transport_destroy */ void (*destroy)(grpc_transport *self); /* implementation of grpc_transport_get_peer */ char *(*get_peer)(grpc_transport *self); } grpc_transport_vtable; /* an instance of a grpc transport */ struct grpc_transport { /* pointer to a vtable defining operations on this transport */ const grpc_transport_vtable *vtable; }; #endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H */ grpc-0.11.1/src/core/transport/chttp2_transport.c0000644000175000017500000013301212600663151022156 0ustar apollockapollock/* * * 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/transport/chttp2_transport.h" #include #include #include #include #include #include #include #include #include "src/core/profiling/timers.h" #include "src/core/support/string.h" #include "src/core/transport/chttp2/http2_errors.h" #include "src/core/transport/chttp2/internal.h" #include "src/core/transport/chttp2/status_conversion.h" #include "src/core/transport/chttp2/timeout_encoding.h" #include "src/core/transport/transport_impl.h" #define DEFAULT_WINDOW 65535 #define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) #define MAX_WINDOW 0x7fffffffu #define MAX_CLIENT_STREAM_ID 0x7fffffffu int grpc_http_trace = 0; int grpc_flowctl_trace = 0; #define TRANSPORT_FROM_WRITING(tw) \ ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ writing))) #define TRANSPORT_FROM_PARSING(tw) \ ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ parsing))) #define TRANSPORT_FROM_GLOBAL(tg) \ ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ global))) #define STREAM_FROM_GLOBAL(sg) \ ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) static const grpc_transport_vtable vtable; static void lock(grpc_chttp2_transport *t); static void unlock(grpc_chttp2_transport *t); static void unlock_check_read_write_state(grpc_chttp2_transport *t); /* forward declarations of various callbacks that we'll build closures around */ static void writing_action(void *t, int iomgr_success_ignored); /** Set a transport level setting, and push it to our peer */ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, gpr_uint32 value); /** Endpoint callback to process incoming data */ static void recv_data(void *tp, int success); /** Start disconnection chain */ static void drop_connection(grpc_chttp2_transport *t); /** Perform a transport_op */ static void perform_stream_op_locked( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op); /** Cancel a stream: coming from the transport API */ static void cancel_from_api(grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_status_code status); static void close_from_api(grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_status_code status, gpr_slice *optional_message); /** Add endpoint from this transport to pollset */ static void add_to_pollset_locked(grpc_chttp2_transport *t, grpc_pollset *pollset); static void add_to_pollset_set_locked(grpc_chttp2_transport *t, grpc_pollset_set *pollset_set); /** Start new streams that have been created if we can */ static void maybe_start_some_streams( grpc_chttp2_transport_global *transport_global); static void connectivity_state_set( grpc_chttp2_transport_global *transport_global, grpc_connectivity_state state, const char *reason); /* * CONSTRUCTION/DESTRUCTION/REFCOUNTING */ static void destruct_transport(grpc_chttp2_transport *t) { size_t i; gpr_mu_lock(&t->mu); GPR_ASSERT(t->ep == NULL); gpr_slice_buffer_destroy(&t->global.qbuf); gpr_slice_buffer_destroy(&t->writing.outbuf); grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor); gpr_slice_buffer_destroy(&t->parsing.qbuf); gpr_slice_buffer_destroy(&t->read_buffer); grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser); grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser); GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout); for (i = 0; i < STREAM_LIST_COUNT; i++) { GPR_ASSERT(t->lists[i].head == NULL); GPR_ASSERT(t->lists[i].tail == NULL); } GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0); GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0); grpc_chttp2_stream_map_destroy(&t->parsing_stream_map); grpc_chttp2_stream_map_destroy(&t->new_stream_map); grpc_connectivity_state_destroy(&t->channel_callback.state_tracker); gpr_mu_unlock(&t->mu); gpr_mu_destroy(&t->mu); /* callback remaining pings: they're not allowed to call into the transpot, and maybe they hold resources that need to be freed */ while (t->global.pings.next != &t->global.pings) { grpc_chttp2_outstanding_ping *ping = t->global.pings.next; grpc_iomgr_add_delayed_callback(ping->on_recv, 0); ping->next->prev = ping->prev; ping->prev->next = ping->next; gpr_free(ping); } grpc_mdctx_unref(t->metadata_context); gpr_free(t->peer_string); gpr_free(t); } #ifdef REFCOUNTING_DEBUG #define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__) #define UNREF_TRANSPORT(t, r) unref_transport(t, r, __FILE__, __LINE__) static void unref_transport(grpc_chttp2_transport *t, const char *reason, const char *file, int line) { gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count, t->refs.count - 1, reason, file, line); if (!gpr_unref(&t->refs)) return; destruct_transport(t); } static void ref_transport(grpc_chttp2_transport *t, const char *reason, const char *file, int line) { gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count, t->refs.count + 1, reason, file, line); gpr_ref(&t->refs); } #else #define REF_TRANSPORT(t, r) ref_transport(t) #define UNREF_TRANSPORT(t, r) unref_transport(t) static void unref_transport(grpc_chttp2_transport *t) { if (!gpr_unref(&t->refs)) return; destruct_transport(t); } static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); } #endif static void init_transport(grpc_chttp2_transport *t, const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *mdctx, int is_client) { size_t i; int j; GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); memset(t, 0, sizeof(*t)); t->base.vtable = &vtable; t->ep = ep; /* one ref is for destroy, the other for when ep becomes NULL */ gpr_ref_init(&t->refs, 2); /* ref is dropped at transport close() */ gpr_ref_init(&t->shutdown_ep_refs, 1); gpr_mu_init(&t->mu); grpc_mdctx_ref(mdctx); t->peer_string = grpc_endpoint_get_peer(ep); t->metadata_context = mdctx; t->endpoint_reading = 1; t->global.next_stream_id = is_client ? 1 : 2; t->global.is_client = is_client; t->global.outgoing_window = DEFAULT_WINDOW; t->global.incoming_window = DEFAULT_WINDOW; t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; t->global.ping_counter = 1; t->global.pings.next = t->global.pings.prev = &t->global.pings; t->parsing.is_client = is_client; t->parsing.str_grpc_timeout = grpc_mdstr_from_string(t->metadata_context, "grpc-timeout", 0); t->parsing.deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->writing.is_client = is_client; grpc_connectivity_state_init(&t->channel_callback.state_tracker, GRPC_CHANNEL_READY, "transport"); gpr_slice_buffer_init(&t->global.qbuf); gpr_slice_buffer_init(&t->writing.outbuf); grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx); grpc_iomgr_closure_init(&t->writing_action, writing_action, t); gpr_slice_buffer_init(&t->parsing.qbuf); grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context); grpc_iomgr_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, &t->writing); grpc_iomgr_closure_init(&t->recv_data, recv_data, t); gpr_slice_buffer_init(&t->read_buffer); if (is_client) { gpr_slice_buffer_add( &t->global.qbuf, gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); } /* 8 is a random stab in the dark as to a good initial size: it's small enough that it shouldn't waste memory for infrequently used connections, yet large enough that the exponential growth should happen nicely when it's needed. TODO(ctiller): tune this */ grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8); grpc_chttp2_stream_map_init(&t->new_stream_map, 8); /* copy in initial settings to all setting sets */ for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value; for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { t->global.settings[j][i] = grpc_chttp2_settings_parameters[i].default_value; } } t->global.dirtied_local_settings = 1; /* Hack: it's common for implementations to assume 65536 bytes initial send window -- this should by rights be 0 */ t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; t->global.sent_local_settings = 0; /* configure http2 the way we like it */ if (is_client) { push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); } push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW); if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) { if (is_client) { gpr_log(GPR_ERROR, "%s: is ignored on the client", GRPC_ARG_MAX_CONCURRENT_STREAMS); } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s: must be an integer", GRPC_ARG_MAX_CONCURRENT_STREAMS); } else { push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, channel_args->args[i].value.integer); } } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { if (channel_args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s: must be an integer", GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER); } else if ((t->global.next_stream_id & 1) != (channel_args->args[i].value.integer & 1)) { gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, t->global.next_stream_id & 1, is_client ? "client" : "server"); } else { t->global.next_stream_id = channel_args->args[i].value.integer; } } } } } static void destroy_transport(grpc_transport *gt) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; lock(t); t->destroying = 1; drop_connection(t); unlock(t); UNREF_TRANSPORT(t, "destroy"); } /** block grpc_endpoint_shutdown being called until a paired allow_endpoint_shutdown is made */ static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) { GPR_ASSERT(t->ep); gpr_ref(&t->shutdown_ep_refs); } static void allow_endpoint_shutdown_locked(grpc_chttp2_transport *t) { if (gpr_unref(&t->shutdown_ep_refs)) { if (t->ep) { grpc_endpoint_shutdown(t->ep); } } } static void allow_endpoint_shutdown_unlocked(grpc_chttp2_transport *t) { if (gpr_unref(&t->shutdown_ep_refs)) { gpr_mu_lock(&t->mu); if (t->ep) { grpc_endpoint_shutdown(t->ep); } gpr_mu_unlock(&t->mu); } } static void destroy_endpoint(grpc_chttp2_transport *t) { grpc_endpoint_destroy(t->ep); t->ep = NULL; UNREF_TRANSPORT( t, "disconnect"); /* safe because we'll still have the ref for write */ } static void close_transport_locked(grpc_chttp2_transport *t) { if (!t->closed) { t->closed = 1; connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE, "close_transport"); if (t->ep) { allow_endpoint_shutdown_locked(t); } } } static int init_stream(grpc_transport *gt, grpc_stream *gs, const void *server_data, grpc_transport_stream_op *initial_op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; memset(s, 0, sizeof(*s)); grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.incoming_metadata); grpc_chttp2_incoming_metadata_buffer_init(&s->global.incoming_metadata); grpc_sopb_init(&s->writing.sopb); grpc_sopb_init(&s->global.incoming_sopb); grpc_chttp2_data_parser_init(&s->parsing.data_parser); REF_TRANSPORT(t, "stream"); lock(t); grpc_chttp2_register_stream(t, s); if (server_data) { GPR_ASSERT(t->parsing_active); s->global.id = (gpr_uint32)(gpr_uintptr)server_data; s->global.outgoing_window = t->global.settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; s->global.max_recv_bytes = s->parsing.incoming_window = s->global.incoming_window = t->global.settings[GRPC_SENT_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); s->global.in_stream_map = 1; } if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op); unlock(t); return 0; } static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; int i; gpr_mu_lock(&t->mu); GPR_ASSERT(s->global.published_state == GRPC_STREAM_CLOSED || s->global.id == 0); GPR_ASSERT(!s->global.in_stream_map); if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { close_transport_locked(t); } if (!t->parsing_active && s->global.id) { GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, s->global.id) == NULL); } grpc_chttp2_list_remove_incoming_window_updated(&t->global, &s->global); grpc_chttp2_list_remove_writable_stream(&t->global, &s->global); gpr_mu_unlock(&t->mu); for (i = 0; i < STREAM_LIST_COUNT; i++) { if (s->included[i]) { gpr_log(GPR_ERROR, "%s stream %d still included in list %d", t->global.is_client ? "client" : "server", s->global.id, i); abort(); } } GPR_ASSERT(s->global.outgoing_sopb == NULL); GPR_ASSERT(s->global.publish_sopb == NULL); grpc_sopb_destroy(&s->writing.sopb); grpc_sopb_destroy(&s->global.incoming_sopb); grpc_chttp2_data_parser_destroy(&s->parsing.data_parser); grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.incoming_metadata); grpc_chttp2_incoming_metadata_buffer_destroy(&s->global.incoming_metadata); grpc_chttp2_incoming_metadata_live_op_buffer_end( &s->global.outstanding_metadata); UNREF_TRANSPORT(t, "stream"); } grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) { grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); grpc_chttp2_stream *s = grpc_chttp2_stream_map_find(&t->parsing_stream_map, id); return s ? &s->parsing : NULL; } grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) { grpc_chttp2_stream *accepting; grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); GPR_ASSERT(t->accepting_stream == NULL); t->accepting_stream = &accepting; t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data, &t->base, (void *)(gpr_uintptr)id); t->accepting_stream = NULL; return &accepting->parsing; } /* * LOCK MANAGEMENT */ /* We take a grpc_chttp2_transport-global lock in response to calls coming in from above, and in response to data being received from below. New data to be written is always queued, as are callbacks to process data. During unlock() we check our todo lists and initiate callbacks and flush writes. */ static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); } static void unlock(grpc_chttp2_transport *t) { grpc_iomgr_closure *run_closures; unlock_check_read_write_state(t); if (!t->writing_active && !t->closed && grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) { t->writing_active = 1; REF_TRANSPORT(t, "writing"); grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1); prevent_endpoint_shutdown(t); } run_closures = t->global.pending_closures_head; t->global.pending_closures_head = NULL; t->global.pending_closures_tail = NULL; gpr_mu_unlock(&t->mu); while (run_closures) { grpc_iomgr_closure *next = run_closures->next; run_closures->cb(run_closures->cb_arg, run_closures->success); run_closures = next; } } /* * OUTPUT PROCESSING */ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, gpr_uint32 value) { const grpc_chttp2_setting_parameters *sp = &grpc_chttp2_settings_parameters[id]; gpr_uint32 use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); if (use_value != value) { gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name, value, use_value); } if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) { t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value; t->global.dirtied_local_settings = 1; } } void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success) { grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr; grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); lock(t); allow_endpoint_shutdown_locked(t); if (!success) { drop_connection(t); } /* cleanup writing related jazz */ grpc_chttp2_cleanup_writing(&t->global, &t->writing); /* leave the writing flag up on shutdown to prevent further writes in unlock() from starting */ t->writing_active = 0; if (t->ep && !t->endpoint_reading) { destroy_endpoint(t); } unlock(t); UNREF_TRANSPORT(t, "writing"); } static void writing_action(void *gt, int iomgr_success_ignored) { grpc_chttp2_transport *t = gt; grpc_chttp2_perform_writes(&t->writing, t->ep); } void grpc_chttp2_add_incoming_goaway( grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error, gpr_slice goaway_text) { char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg); gpr_free(msg); gpr_slice_unref(goaway_text); transport_global->seen_goaway = 1; connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE, "got_goaway"); } static void maybe_start_some_streams( grpc_chttp2_transport_global *transport_global) { grpc_chttp2_stream_global *stream_global; /* start streams where we have free grpc_chttp2_stream ids and free * concurrency */ while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID && transport_global->concurrent_stream_count < transport_global ->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] && grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, &stream_global)) { GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d", transport_global->is_client ? "CLI" : "SVR", stream_global, transport_global->next_stream_id)); GPR_ASSERT(stream_global->id == 0); stream_global->id = transport_global->next_stream_id; transport_global->next_stream_id += 2; if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) { connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE, "no_more_stream_ids"); } stream_global->outgoing_window = transport_global->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; stream_global->incoming_window = transport_global->settings[GRPC_SENT_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; stream_global->max_recv_bytes = GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes); grpc_chttp2_stream_map_add( &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map, stream_global->id, STREAM_FROM_GLOBAL(stream_global)); stream_global->in_stream_map = 1; transport_global->concurrent_stream_count++; grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } /* cancel out streams that will never be started */ while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, &stream_global)) { cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE); } } static void perform_stream_op_locked( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) { if (op->cancel_with_status != GRPC_STATUS_OK) { cancel_from_api(transport_global, stream_global, op->cancel_with_status); } if (op->close_with_status != GRPC_STATUS_OK) { close_from_api(transport_global, stream_global, op->close_with_status, op->optional_close_message); } if (op->send_ops) { GPR_ASSERT(stream_global->outgoing_sopb == NULL); stream_global->send_done_closure = op->on_done_send; if (!stream_global->cancelled) { stream_global->written_anything = 1; stream_global->outgoing_sopb = op->send_ops; if (op->is_last_send && stream_global->write_state == GRPC_WRITE_STATE_OPEN) { stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE; } if (stream_global->id == 0) { GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_DEBUG, "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency", transport_global->is_client ? "CLI" : "SVR", stream_global)); grpc_chttp2_list_add_waiting_for_concurrency(transport_global, stream_global); maybe_start_some_streams(transport_global); } else if (stream_global->outgoing_window > 0) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } } else { grpc_sopb_reset(op->send_ops); grpc_chttp2_schedule_closure(transport_global, stream_global->send_done_closure, 0); } } if (op->recv_ops) { GPR_ASSERT(stream_global->publish_sopb == NULL); GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED); stream_global->recv_done_closure = op->on_done_recv; stream_global->publish_sopb = op->recv_ops; stream_global->publish_sopb->nops = 0; stream_global->publish_state = op->recv_state; if (stream_global->max_recv_bytes < op->max_recv_bytes) { GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "op", transport_global, stream_global, max_recv_bytes, op->max_recv_bytes - stream_global->max_recv_bytes); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "op", transport_global, stream_global, unannounced_incoming_window, op->max_recv_bytes - stream_global->max_recv_bytes); stream_global->unannounced_incoming_window += op->max_recv_bytes - stream_global->max_recv_bytes; stream_global->max_recv_bytes = op->max_recv_bytes; } grpc_chttp2_incoming_metadata_live_op_buffer_end( &stream_global->outstanding_metadata); grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); if (stream_global->id != 0) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } } if (op->bind_pollset) { add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global), op->bind_pollset); } if (op->on_consumed) { grpc_chttp2_schedule_closure(transport_global, op->on_consumed, 1); } } static void perform_stream_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_stream_op *op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; lock(t); perform_stream_op_locked(&t->global, &s->global, op); unlock(t); } static void send_ping_locked(grpc_chttp2_transport *t, grpc_iomgr_closure *on_recv) { grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); p->next = &t->global.pings; p->prev = p->next->prev; p->prev->next = p->next->prev = p; p->id[0] = (t->global.ping_counter >> 56) & 0xff; p->id[1] = (t->global.ping_counter >> 48) & 0xff; p->id[2] = (t->global.ping_counter >> 40) & 0xff; p->id[3] = (t->global.ping_counter >> 32) & 0xff; p->id[4] = (t->global.ping_counter >> 24) & 0xff; p->id[5] = (t->global.ping_counter >> 16) & 0xff; p->id[6] = (t->global.ping_counter >> 8) & 0xff; p->id[7] = t->global.ping_counter & 0xff; p->on_recv = on_recv; gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id)); } static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; int close_transport = 0; lock(t); if (op->on_consumed) { grpc_chttp2_schedule_closure(&t->global, op->on_consumed, 1); } if (op->on_connectivity_state_change) { grpc_connectivity_state_notify_on_state_change( &t->channel_callback.state_tracker, op->connectivity_state, op->on_connectivity_state_change); } if (op->send_goaway) { t->global.sent_goaway = 1; grpc_chttp2_goaway_append( t->global.last_incoming_stream_id, grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), gpr_slice_ref(*op->goaway_message), &t->global.qbuf); close_transport = !grpc_chttp2_has_streams(t); } if (op->set_accept_stream != NULL) { t->channel_callback.accept_stream = op->set_accept_stream; t->channel_callback.accept_stream_user_data = op->set_accept_stream_user_data; } if (op->bind_pollset) { add_to_pollset_locked(t, op->bind_pollset); } if (op->bind_pollset_set) { add_to_pollset_set_locked(t, op->bind_pollset_set); } if (op->send_ping) { send_ping_locked(t, op->send_ping); } if (op->disconnect) { close_transport_locked(t); } unlock(t); if (close_transport) { lock(t); close_transport_locked(t); unlock(t); } } /* * INPUT PROCESSING */ static grpc_stream_state compute_state(gpr_uint8 write_closed, gpr_uint8 read_closed) { if (write_closed && read_closed) return GRPC_STREAM_CLOSED; if (write_closed) return GRPC_STREAM_SEND_CLOSED; if (read_closed) return GRPC_STREAM_RECV_CLOSED; return GRPC_STREAM_OPEN; } static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) { size_t new_stream_count; grpc_chttp2_stream *s = grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); if (!s) { s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id); } grpc_chttp2_list_remove_writable_stream(&t->global, &s->global); GPR_ASSERT(s); s->global.in_stream_map = 0; if (t->parsing.incoming_stream == &s->parsing) { t->parsing.incoming_stream = NULL; grpc_chttp2_parsing_become_skip_parser(&t->parsing); } if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { close_transport_locked(t); } new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) + grpc_chttp2_stream_map_size(&t->new_stream_map); if (new_stream_count != t->global.concurrent_stream_count) { t->global.concurrent_stream_count = new_stream_count; maybe_start_some_streams(&t->global); } } static void unlock_check_read_write_state(grpc_chttp2_transport *t) { grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_stream_global *stream_global; grpc_stream_state state; if (!t->parsing_active) { /* if a stream is in the stream map, and gets cancelled, we need to ensure we are not parsing before continuing the cancellation to keep things in a sane state */ while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global, &stream_global)) { GPR_ASSERT(stream_global->in_stream_map); GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN); GPR_ASSERT(stream_global->read_closed); remove_stream(t, stream_global->id); grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } } if (!t->writing_active) { while (grpc_chttp2_list_pop_cancelled_waiting_for_writing(transport_global, &stream_global)) { grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } } while (grpc_chttp2_list_pop_read_write_state_changed(transport_global, &stream_global)) { if (stream_global->cancelled) { if (t->writing_active && stream_global->write_state != GRPC_WRITE_STATE_SENT_CLOSE) { grpc_chttp2_list_add_cancelled_waiting_for_writing(transport_global, stream_global); } else { stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE; if (stream_global->outgoing_sopb != NULL) { grpc_sopb_reset(stream_global->outgoing_sopb); stream_global->outgoing_sopb = NULL; grpc_chttp2_schedule_closure(transport_global, stream_global->send_done_closure, 1); } stream_global->read_closed = 1; if (!stream_global->published_cancelled) { char buffer[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(stream_global->cancelled_status, buffer); grpc_chttp2_incoming_metadata_buffer_add( &stream_global->incoming_metadata, grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer)); grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into( &stream_global->incoming_metadata, &stream_global->incoming_sopb); stream_global->published_cancelled = 1; } } } if (stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE && stream_global->read_closed && stream_global->in_stream_map) { if (t->parsing_active) { grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, stream_global); } else { remove_stream(t, stream_global->id); } } if (!stream_global->publish_sopb) { continue; } if (stream_global->writing_now != 0) { continue; } /* FIXME(ctiller): we include in_stream_map in our computation of whether the stream is write-closed. This is completely bogus, but has the effect of delaying stream-closed until the stream is indeed evicted from the stream map, making it safe to delete. To fix this will require having an edge after stream-closed indicating that the stream is closed AND safe to delete. */ state = compute_state( stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE && !stream_global->in_stream_map, stream_global->read_closed); if (stream_global->incoming_sopb.nops == 0 && state == stream_global->published_state) { continue; } grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op( &stream_global->incoming_metadata, &stream_global->incoming_sopb, &stream_global->outstanding_metadata); grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb); stream_global->published_state = *stream_global->publish_state = state; grpc_chttp2_schedule_closure(transport_global, stream_global->recv_done_closure, 1); stream_global->recv_done_closure = NULL; stream_global->publish_sopb = NULL; stream_global->publish_state = NULL; } } static void cancel_from_api(grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_status_code status) { stream_global->cancelled = 1; stream_global->cancelled_status = status; if (stream_global->id != 0) { gpr_slice_buffer_add( &transport_global->qbuf, grpc_chttp2_rst_stream_create( stream_global->id, grpc_chttp2_grpc_status_to_http2_error(status))); } grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } static void close_from_api(grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_status_code status, gpr_slice *optional_message) { gpr_slice hdr; gpr_slice status_hdr; gpr_slice message_pfx; gpr_uint8 *p; gpr_uint32 len = 0; GPR_ASSERT(status >= 0 && (int)status < 100); stream_global->cancelled = 1; stream_global->cancelled_status = status; GPR_ASSERT(stream_global->id != 0); GPR_ASSERT(!stream_global->written_anything); /* Hand roll a header block. This is unnecessarily ugly - at some point we should find a more elegant solution. It's complicated by the fact that our send machinery would be dead by the time we got around to sending this, so instead we ignore HPACK compression and just write the uncompressed bytes onto the wire. */ status_hdr = gpr_slice_malloc(15 + (status >= 10)); p = GPR_SLICE_START_PTR(status_hdr); *p++ = 0x40; /* literal header */ *p++ = 11; /* len(grpc-status) */ *p++ = 'g'; *p++ = 'r'; *p++ = 'p'; *p++ = 'c'; *p++ = '-'; *p++ = 's'; *p++ = 't'; *p++ = 'a'; *p++ = 't'; *p++ = 'u'; *p++ = 's'; if (status < 10) { *p++ = 1; *p++ = '0' + status; } else { *p++ = 2; *p++ = '0' + (status / 10); *p++ = '0' + (status % 10); } GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr)); len += GPR_SLICE_LENGTH(status_hdr); if (optional_message) { GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127); message_pfx = gpr_slice_malloc(15); p = GPR_SLICE_START_PTR(message_pfx); *p++ = 0x40; *p++ = 12; /* len(grpc-message) */ *p++ = 'g'; *p++ = 'r'; *p++ = 'p'; *p++ = 'c'; *p++ = '-'; *p++ = 'm'; *p++ = 'e'; *p++ = 's'; *p++ = 's'; *p++ = 'a'; *p++ = 'g'; *p++ = 'e'; *p++ = GPR_SLICE_LENGTH(*optional_message); GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx)); len += GPR_SLICE_LENGTH(message_pfx); len += GPR_SLICE_LENGTH(*optional_message); } hdr = gpr_slice_malloc(9); p = GPR_SLICE_START_PTR(hdr); *p++ = len >> 16; *p++ = len >> 8; *p++ = len; *p++ = GRPC_CHTTP2_FRAME_HEADER; *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; *p++ = stream_global->id >> 24; *p++ = stream_global->id >> 16; *p++ = stream_global->id >> 8; *p++ = stream_global->id; GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr)); gpr_slice_buffer_add(&transport_global->qbuf, hdr); gpr_slice_buffer_add(&transport_global->qbuf, status_hdr); if (optional_message) { gpr_slice_buffer_add(&transport_global->qbuf, message_pfx); gpr_slice_buffer_add(&transport_global->qbuf, gpr_slice_ref(*optional_message)); } gpr_slice_buffer_add( &transport_global->qbuf, grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR)); grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, void *user_data, grpc_chttp2_stream_global *stream_global) { cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE); } static void end_all_the_calls(grpc_chttp2_transport *t) { grpc_chttp2_for_all_streams(&t->global, NULL, cancel_stream_cb); } static void drop_connection(grpc_chttp2_transport *t) { close_transport_locked(t); end_all_the_calls(t); } /** update window from a settings change */ static void update_global_window(void *args, gpr_uint32 id, void *stream) { grpc_chttp2_transport *t = args; grpc_chttp2_stream *s = stream; grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_stream_global *stream_global = &s->global; int was_zero; int is_zero; GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global, outgoing_window, t->parsing.initial_window_update); was_zero = stream_global->outgoing_window <= 0; stream_global->outgoing_window += t->parsing.initial_window_update; is_zero = stream_global->outgoing_window <= 0; if (was_zero && !is_zero) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } } static void read_error_locked(grpc_chttp2_transport *t) { t->endpoint_reading = 0; if (!t->writing_active && t->ep) { destroy_endpoint(t); } } /* tcp read callback */ static int recv_data_loop(grpc_chttp2_transport *t, int *success) { size_t i; int keep_reading = 0; lock(t); i = 0; GPR_ASSERT(!t->parsing_active); if (!t->closed) { t->parsing_active = 1; /* merge stream lists */ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); grpc_chttp2_prepare_to_read(&t->global, &t->parsing); gpr_mu_unlock(&t->mu); for (; i < t->read_buffer.count && grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]); i++) ; gpr_mu_lock(&t->mu); if (i != t->read_buffer.count) { drop_connection(t); } /* merge stream lists */ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); t->global.concurrent_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map); if (t->parsing.initial_window_update != 0) { grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, update_global_window, t); t->parsing.initial_window_update = 0; } /* handle higher level things */ grpc_chttp2_publish_reads(&t->global, &t->parsing); t->parsing_active = 0; } if (!*success || i != t->read_buffer.count) { drop_connection(t); read_error_locked(t); } else if (!t->closed) { keep_reading = 1; REF_TRANSPORT(t, "keep_reading"); prevent_endpoint_shutdown(t); } gpr_slice_buffer_reset_and_unref(&t->read_buffer); unlock(t); if (keep_reading) { int ret = -1; switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) { case GRPC_ENDPOINT_DONE: *success = 1; ret = 1; break; case GRPC_ENDPOINT_ERROR: *success = 0; ret = 1; break; case GRPC_ENDPOINT_PENDING: ret = 0; break; } allow_endpoint_shutdown_unlocked(t); UNREF_TRANSPORT(t, "keep_reading"); return ret; } else { UNREF_TRANSPORT(t, "recv_data"); return 0; } gpr_log(GPR_ERROR, "should never reach here"); abort(); } static void recv_data(void *tp, int success) { grpc_chttp2_transport *t = tp; while (recv_data_loop(t, &success)) ; } /* * CALLBACK LOOP */ static void schedule_closure_for_connectivity(void *a, grpc_iomgr_closure *closure) { grpc_chttp2_schedule_closure(a, closure, 1); } static void connectivity_state_set( grpc_chttp2_transport_global *transport_global, grpc_connectivity_state state, const char *reason) { GRPC_CHTTP2_IF_TRACING( gpr_log(GPR_DEBUG, "set connectivity_state=%d", state)); grpc_connectivity_state_set_with_scheduler( &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker, state, schedule_closure_for_connectivity, transport_global, reason); } void grpc_chttp2_schedule_closure( grpc_chttp2_transport_global *transport_global, grpc_iomgr_closure *closure, int success) { closure->success = success; if (transport_global->pending_closures_tail == NULL) { transport_global->pending_closures_head = transport_global->pending_closures_tail = closure; } else { transport_global->pending_closures_tail->next = closure; transport_global->pending_closures_tail = closure; } closure->next = NULL; } /* * POLLSET STUFF */ static void add_to_pollset_locked(grpc_chttp2_transport *t, grpc_pollset *pollset) { if (t->ep) { grpc_endpoint_add_to_pollset(t->ep, pollset); } } static void add_to_pollset_set_locked(grpc_chttp2_transport *t, grpc_pollset_set *pollset_set) { if (t->ep) { grpc_endpoint_add_to_pollset_set(t->ep, pollset_set); } } /* * TRACING */ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason, const char *context, const char *var, int is_client, gpr_uint32 stream_id, gpr_int64 current_value, gpr_int64 delta) { char *identifier; char *context_scope; char *context_thread; char *underscore_pos = strchr(context, '_'); GPR_ASSERT(underscore_pos); context_thread = gpr_strdup(underscore_pos + 1); context_scope = gpr_strdup(context); context_scope[underscore_pos - context] = 0; if (stream_id) { gpr_asprintf(&identifier, "%s[%d]", context_scope, stream_id); } else { identifier = gpr_strdup(context_scope); } gpr_log(GPR_INFO, "FLOWCTL: %s %-10s %8s %-27s %8lld %c %8lld = %8lld %-10s [%s:%d]", is_client ? "client" : "server", identifier, context_thread, var, current_value, delta < 0 ? '-' : '+', delta < 0 ? -delta : delta, current_value + delta, reason, file, line); gpr_free(identifier); gpr_free(context_thread); gpr_free(context_scope); } /* * INTEGRATION GLUE */ static char *chttp2_get_peer(grpc_transport *t) { return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string); } static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), init_stream, perform_stream_op, perform_transport_op, destroy_stream, destroy_transport, chttp2_get_peer}; grpc_transport *grpc_create_chttp2_transport( const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *mdctx, int is_client) { grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport)); init_transport(t, channel_args, ep, mdctx, is_client); return &t->base; } void grpc_chttp2_transport_start_reading(grpc_transport *transport, gpr_slice *slices, size_t nslices) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */ gpr_slice_buffer_addn(&t->read_buffer, slices, nslices); recv_data(t, 1); } grpc-0.11.1/src/core/transport/metadata.h0000644000175000017500000002035412600663151020427 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H #define GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H #include #include /* This file provides a mechanism for tracking metadata through the grpc stack. It's not intended for consumption outside of the library. Metadata is tracked in the context of a grpc_mdctx. For the time being there is one of these per-channel, avoiding cross channel interference with memory use and lock contention. The context tracks unique strings (grpc_mdstr) and pairs of strings (grpc_mdelem). Any of these objects can be checked for equality by comparing their pointers. These objects are reference counted. grpc_mdelem can additionally store a (non-NULL) user data pointer. This pointer is intended to be used to cache semantic meaning of a metadata element. For example, an OAuth token may cache the credentials it represents and the time at which it expires in the mdelem user data. Combining this metadata cache and the hpack compression table allows us to simply lookup complete preparsed objects quickly, incurring a few atomic ops per metadata element on the fast path. grpc_mdelem instances MAY live longer than their refcount implies, and are garbage collected periodically, meaning cached data can easily outlive a single request. */ /* Forward declarations */ typedef struct grpc_mdctx grpc_mdctx; typedef struct grpc_mdstr grpc_mdstr; typedef struct grpc_mdelem grpc_mdelem; /* if changing this, make identical changes in internal_string in metadata.c */ struct grpc_mdstr { const gpr_slice slice; const gpr_uint32 hash; /* there is a private part to this in metadata.c */ }; /* if changing this, make identical changes in internal_metadata in metadata.c */ struct grpc_mdelem { grpc_mdstr *const key; grpc_mdstr *const value; /* there is a private part to this in metadata.c */ }; /* Create/orphan a metadata context */ grpc_mdctx *grpc_mdctx_create(void); grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed); void grpc_mdctx_ref(grpc_mdctx *mdctx); void grpc_mdctx_unref(grpc_mdctx *mdctx); /* Test only accessors to internal state - only for testing this code - do not rely on it outside of metadata_test.c */ size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *mdctx); size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *mdctx); size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx); /* Constructors for grpc_mdstr instances; take a variety of data types that clients may have handy */ grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int perform_key_canonicalization); /* Unrefs the slice. */ grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice); grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str, size_t length); /* Returns a borrowed slice from the mdstr with its contents base64 encoded and huffman compressed */ gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str); /* Constructors for grpc_mdelem instances; take a variety of data types that clients may have handy */ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdstr *key, grpc_mdstr *value); grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key, const char *value); /* Unrefs the slices. */ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, gpr_slice value); grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx, const char *key, const gpr_uint8 *value, size_t value_length, int canonicalize_key); /* Mutator and accessor for grpc_mdelem user data. The destructor function is used as a type tag and is checked during user_data fetch. */ void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*if_destroy_func)(void *)); void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), void *user_data); /* Reference counting */ #ifdef GRPC_METADATA_REFCOUNT_DEBUG #define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__) #define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s), __FILE__, __LINE__) #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__) #define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__) grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line); void grpc_mdstr_unref(grpc_mdstr *s, const char *file, int line); grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line); void grpc_mdelem_unref(grpc_mdelem *md, const char *file, int line); #else #define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s)) #define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s)) #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s)) #define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s)) grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s); void grpc_mdstr_unref(grpc_mdstr *s); grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md); void grpc_mdelem_unref(grpc_mdelem *md); #endif /* Recover a char* from a grpc_mdstr. The returned string is null terminated. Does not promise that the returned string has no embedded nulls however. */ const char *grpc_mdstr_as_c_string(grpc_mdstr *s); int grpc_mdstr_is_legal_header(grpc_mdstr *s); int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s); int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s); /* Batch mode metadata functions. These API's have equivalents above, but allow taking the mdctx just once, performing a bunch of work, and then leaving the mdctx. */ /* Lock the metadata context: it's only safe to call _locked_ functions against this context from the calling thread until grpc_mdctx_unlock is called */ void grpc_mdctx_lock(grpc_mdctx *ctx); #ifdef GRPC_METADATA_REFCOUNT_DEBUG #define GRPC_MDCTX_LOCKED_MDELEM_UNREF(ctx, elem) \ grpc_mdctx_locked_mdelem_unref((ctx), (elem), __FILE__, __LINE__) /* Unref a metadata element */ void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *elem, const char *file, int line); #else #define GRPC_MDCTX_LOCKED_MDELEM_UNREF(ctx, elem) \ grpc_mdctx_locked_mdelem_unref((ctx), (elem)) /* Unref a metadata element */ void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *elem); #endif /* Unlock the metadata context */ void grpc_mdctx_unlock(grpc_mdctx *ctx); #define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash)) #endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */ grpc-0.11.1/src/core/transport/transport.h0000644000175000017500000001751112600663151020704 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H #define GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H #include #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_set.h" #include "src/core/transport/stream_op.h" #include "src/core/channel/context.h" /* forward declarations */ typedef struct grpc_transport grpc_transport; /* grpc_stream doesn't actually exist. It's used as a typesafe opaque pointer for whatever data the transport wants to track for a stream. */ typedef struct grpc_stream grpc_stream; /* Represents the send/recv closed state of a stream. */ typedef enum grpc_stream_state { /* the stream is open for sends and receives */ GRPC_STREAM_OPEN, /* the stream is closed for sends, but may still receive data */ GRPC_STREAM_SEND_CLOSED, /* the stream is closed for receives, but may still send data */ GRPC_STREAM_RECV_CLOSED, /* the stream is closed for both sends and receives */ GRPC_STREAM_CLOSED } grpc_stream_state; /* Transport stream op: a set of operations to perform on a transport against a single stream */ typedef struct grpc_transport_stream_op { grpc_iomgr_closure *on_consumed; grpc_stream_op_buffer *send_ops; int is_last_send; grpc_iomgr_closure *on_done_send; grpc_stream_op_buffer *recv_ops; grpc_stream_state *recv_state; /** The number of bytes this peer is currently prepared to receive. These bytes will be eventually used to replenish per-stream flow control windows. */ gpr_uint32 max_recv_bytes; grpc_iomgr_closure *on_done_recv; grpc_pollset *bind_pollset; /** If != GRPC_STATUS_OK, cancel this stream */ grpc_status_code cancel_with_status; /** If != GRPC_STATUS_OK, send grpc-status, grpc-message, and close this stream for both reading and writing */ grpc_status_code close_with_status; gpr_slice *optional_close_message; /* Indexes correspond to grpc_context_index enum values */ grpc_call_context_element *context; } grpc_transport_stream_op; /** Transport op: a set of operations to perform on a transport as a whole */ typedef struct grpc_transport_op { /** called when processing of this op is done */ grpc_iomgr_closure *on_consumed; /** connectivity monitoring */ grpc_iomgr_closure *on_connectivity_state_change; grpc_connectivity_state *connectivity_state; /** should the transport be disconnected */ int disconnect; /** should we send a goaway? after a goaway is sent, once there are no more active calls on the transport, the transport should disconnect */ int send_goaway; /** what should the goaway contain? */ grpc_status_code goaway_status; gpr_slice *goaway_message; /** set the callback for accepting new streams; this is a permanent callback, unlike the other one-shot closures */ void (*set_accept_stream)(void *user_data, grpc_transport *transport, const void *server_data); void *set_accept_stream_user_data; /** add this transport to a pollset */ grpc_pollset *bind_pollset; /** add this transport to a pollset_set */ grpc_pollset_set *bind_pollset_set; /** send a ping, call this back if not NULL */ grpc_iomgr_closure *send_ping; } grpc_transport_op; /* Returns the amount of memory required to store a grpc_stream for this transport */ size_t grpc_transport_stream_size(grpc_transport *transport); /* Initialize transport data for a stream. Returns 0 on success, any other (transport-defined) value for failure. Arguments: transport - the transport on which to create this stream stream - a pointer to uninitialized memory to initialize server_data - either NULL for a client initiated stream, or a pointer supplied from the accept_stream callback function */ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, const void *server_data, grpc_transport_stream_op *initial_op); /* Destroy transport data for a stream. Requires: a recv_batch with final_state == GRPC_STREAM_CLOSED has been received by the up-layer. Must not be called in the same call stack as recv_frame. Arguments: transport - the transport on which to create this stream stream - the grpc_stream to destroy (memory is still owned by the caller, but any child memory must be cleaned up) */ void grpc_transport_destroy_stream(grpc_transport *transport, grpc_stream *stream); void grpc_transport_stream_op_finish_with_failure(grpc_transport_stream_op *op); void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, grpc_status_code status); void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, grpc_status_code status, gpr_slice *optional_message); char *grpc_transport_stream_op_string(grpc_transport_stream_op *op); /* Send a batch of operations on a transport Takes ownership of any objects contained in ops. Arguments: transport - the transport on which to initiate the stream stream - the stream on which to send the operations. This must be non-NULL and previously initialized by the same transport. op - a grpc_transport_stream_op specifying the op to perform */ void grpc_transport_perform_stream_op(grpc_transport *transport, grpc_stream *stream, grpc_transport_stream_op *op); void grpc_transport_perform_op(grpc_transport *transport, grpc_transport_op *op); /* Send a ping on a transport Calls cb with user data when a response is received. */ void grpc_transport_ping(grpc_transport *transport, grpc_iomgr_closure *cb); /* Advise peer of pending connection termination. */ void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status, gpr_slice debug_data); /* Close a transport. Aborts all open streams. */ void grpc_transport_close(grpc_transport *transport); /* Destroy the transport */ void grpc_transport_destroy(grpc_transport *transport); /* Get the transports peer */ char *grpc_transport_get_peer(grpc_transport *transport); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */ grpc-0.11.1/src/core/transport/connectivity_state.c0000644000175000017500000001224612600663151022561 0ustar apollockapollock/* * * 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/transport/connectivity_state.h" #include #include #include int grpc_connectivity_state_trace = 0; const char *grpc_connectivity_state_name(grpc_connectivity_state state) { switch (state) { case GRPC_CHANNEL_IDLE: return "IDLE"; case GRPC_CHANNEL_CONNECTING: return "CONNECTING"; case GRPC_CHANNEL_READY: return "READY"; case GRPC_CHANNEL_TRANSIENT_FAILURE: return "TRANSIENT_FAILURE"; case GRPC_CHANNEL_FATAL_FAILURE: return "FATAL_FAILURE"; } abort(); return "UNKNOWN"; } void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, grpc_connectivity_state init_state, const char *name) { tracker->current_state = init_state; tracker->watchers = NULL; tracker->name = gpr_strdup(name); } void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) { grpc_connectivity_state_watcher *w; while ((w = tracker->watchers)) { tracker->watchers = w->next; if (GRPC_CHANNEL_FATAL_FAILURE != *w->current) { *w->current = GRPC_CHANNEL_FATAL_FAILURE; grpc_iomgr_add_callback(w->notify); } else { grpc_iomgr_add_delayed_callback(w->notify, 0); } gpr_free(w); } gpr_free(tracker->name); } grpc_connectivity_state grpc_connectivity_state_check( grpc_connectivity_state_tracker *tracker) { return tracker->current_state; } int grpc_connectivity_state_notify_on_state_change( grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current, grpc_iomgr_closure *notify) { if (grpc_connectivity_state_trace) { gpr_log(GPR_DEBUG, "CONWATCH: %s: from %s [cur=%s]", tracker->name, grpc_connectivity_state_name(*current), grpc_connectivity_state_name(tracker->current_state)); } if (tracker->current_state != *current) { *current = tracker->current_state; grpc_iomgr_add_callback(notify); } else { grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w)); w->current = current; w->notify = notify; w->next = tracker->watchers; tracker->watchers = w; } return tracker->current_state == GRPC_CHANNEL_IDLE; } void grpc_connectivity_state_set_with_scheduler( grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg, const char *reason) { grpc_connectivity_state_watcher *new = NULL; grpc_connectivity_state_watcher *w; if (grpc_connectivity_state_trace) { gpr_log(GPR_DEBUG, "SET: %s: %s --> %s [%s]", tracker->name, grpc_connectivity_state_name(tracker->current_state), grpc_connectivity_state_name(state), reason); } if (tracker->current_state == state) { return; } GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_FATAL_FAILURE); tracker->current_state = state; while ((w = tracker->watchers)) { tracker->watchers = w->next; if (state != *w->current) { *w->current = state; scheduler(arg, w->notify); gpr_free(w); } else { w->next = new; new = w; } } tracker->watchers = new; } static void default_scheduler(void *ignored, grpc_iomgr_closure *closure) { grpc_iomgr_add_callback(closure); } void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, const char *reason) { grpc_connectivity_state_set_with_scheduler(tracker, state, default_scheduler, NULL, reason); } grpc-0.11.1/src/core/transport/connectivity_state.h0000644000175000017500000000661512600663151022571 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H #define GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H #include #include "src/core/iomgr/iomgr.h" typedef struct grpc_connectivity_state_watcher { /** we keep watchers in a linked list */ struct grpc_connectivity_state_watcher *next; /** closure to notify on change */ grpc_iomgr_closure *notify; /** the current state as believed by the watcher */ grpc_connectivity_state *current; } grpc_connectivity_state_watcher; typedef struct { /** current connectivity state */ grpc_connectivity_state current_state; /** all our watchers */ grpc_connectivity_state_watcher *watchers; /** a name to help debugging */ char *name; } grpc_connectivity_state_tracker; extern int grpc_connectivity_state_trace; void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, grpc_connectivity_state init_state, const char *name); void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker); void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, const char *reason); void grpc_connectivity_state_set_with_scheduler( grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg, const char *reason); grpc_connectivity_state grpc_connectivity_state_check( grpc_connectivity_state_tracker *tracker); /** Return 1 if the channel should start connecting, 0 otherwise */ int grpc_connectivity_state_notify_on_state_change( grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current, grpc_iomgr_closure *notify); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */ grpc-0.11.1/src/core/transport/chttp2/0000755000175000017500000000000012600663151017676 5ustar apollockapollockgrpc-0.11.1/src/core/transport/chttp2/frame_data.c0000644000175000017500000001350512600663151022131 0ustar apollockapollock/* * * 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/transport/chttp2/frame_data.h" #include #include "src/core/transport/chttp2/internal.h" #include "src/core/support/string.h" #include #include #include #include "src/core/transport/transport.h" grpc_chttp2_parse_error grpc_chttp2_data_parser_init( grpc_chttp2_data_parser *parser) { parser->state = GRPC_CHTTP2_DATA_FH_0; grpc_sopb_init(&parser->incoming_sopb); return GRPC_CHTTP2_PARSE_OK; } void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser *parser) { grpc_sopb_destroy(&parser->incoming_sopb); } grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( grpc_chttp2_data_parser *parser, gpr_uint8 flags) { if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) { gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags); return GRPC_CHTTP2_STREAM_ERROR; } if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) { parser->is_last_frame = 1; } else { parser->is_last_frame = 0; } return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *const end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; grpc_chttp2_data_parser *p = parser; gpr_uint32 message_flags = 0; if (is_last && p->is_last_frame) { stream_parsing->received_close = 1; } if (cur == end) { return GRPC_CHTTP2_PARSE_OK; } switch (p->state) { fh_0: case GRPC_CHTTP2_DATA_FH_0: p->frame_type = *cur; switch (p->frame_type) { case 0: p->is_frame_compressed = 0; /* GPR_FALSE */ break; case 1: p->is_frame_compressed = 1; /* GPR_TRUE */ break; default: gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); return GRPC_CHTTP2_STREAM_ERROR; } if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_1; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_1: p->frame_size = ((gpr_uint32)*cur) << 24; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_2; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_2: p->frame_size |= ((gpr_uint32)*cur) << 16; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_3; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_3: p->frame_size |= ((gpr_uint32)*cur) << 8; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_4; return GRPC_CHTTP2_PARSE_OK; } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_4: p->frame_size |= ((gpr_uint32)*cur); p->state = GRPC_CHTTP2_DATA_FRAME; ++cur; if (p->is_frame_compressed) { message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } grpc_sopb_add_begin_message(&p->incoming_sopb, p->frame_size, message_flags); /* fallthrough */ case GRPC_CHTTP2_DATA_FRAME: if (cur == end) { grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); if ((gpr_uint32)(end - cur) == p->frame_size) { grpc_sopb_add_slice(&p->incoming_sopb, gpr_slice_sub(slice, cur - beg, end - beg)); p->state = GRPC_CHTTP2_DATA_FH_0; return GRPC_CHTTP2_PARSE_OK; } else if ((gpr_uint32)(end - cur) > p->frame_size) { grpc_sopb_add_slice( &p->incoming_sopb, gpr_slice_sub(slice, cur - beg, cur + p->frame_size - beg)); cur += p->frame_size; goto fh_0; /* loop */ } else { grpc_sopb_add_slice(&p->incoming_sopb, gpr_slice_sub(slice, cur - beg, end - beg)); p->frame_size -= (end - cur); return GRPC_CHTTP2_PARSE_OK; } } gpr_log(GPR_ERROR, "should never reach here"); abort(); return GRPC_CHTTP2_CONNECTION_ERROR; } grpc-0.11.1/src/core/transport/chttp2/internal.h0000644000175000017500000005642212600663151021674 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H #define GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H #include "src/core/iomgr/endpoint.h" #include "src/core/transport/chttp2/frame.h" #include "src/core/transport/chttp2/frame_data.h" #include "src/core/transport/chttp2/frame_goaway.h" #include "src/core/transport/chttp2/frame_ping.h" #include "src/core/transport/chttp2/frame_rst_stream.h" #include "src/core/transport/chttp2/frame_settings.h" #include "src/core/transport/chttp2/frame_window_update.h" #include "src/core/transport/chttp2/hpack_parser.h" #include "src/core/transport/chttp2/incoming_metadata.h" #include "src/core/transport/chttp2/stream_encoder.h" #include "src/core/transport/chttp2/stream_map.h" #include "src/core/transport/connectivity_state.h" #include "src/core/transport/transport_impl.h" typedef struct grpc_chttp2_transport grpc_chttp2_transport; typedef struct grpc_chttp2_stream grpc_chttp2_stream; /* streams are kept in various linked lists depending on what things need to happen to them... this enum labels each list */ typedef enum { GRPC_CHTTP2_LIST_ALL_STREAMS, GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED, GRPC_CHTTP2_LIST_WRITABLE, GRPC_CHTTP2_LIST_WRITING, GRPC_CHTTP2_LIST_WRITTEN, GRPC_CHTTP2_LIST_PARSING_SEEN, GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING, GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING, GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED, /** streams that are waiting to start because there are too many concurrent streams on the connection */ GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY, STREAM_LIST_COUNT /* must be last */ } grpc_chttp2_stream_list_id; /* deframer state for the overall http2 stream of bytes */ typedef enum { /* prefix: one entry per http2 connection prefix byte */ GRPC_DTS_CLIENT_PREFIX_0 = 0, GRPC_DTS_CLIENT_PREFIX_1, GRPC_DTS_CLIENT_PREFIX_2, GRPC_DTS_CLIENT_PREFIX_3, GRPC_DTS_CLIENT_PREFIX_4, GRPC_DTS_CLIENT_PREFIX_5, GRPC_DTS_CLIENT_PREFIX_6, GRPC_DTS_CLIENT_PREFIX_7, GRPC_DTS_CLIENT_PREFIX_8, GRPC_DTS_CLIENT_PREFIX_9, GRPC_DTS_CLIENT_PREFIX_10, GRPC_DTS_CLIENT_PREFIX_11, GRPC_DTS_CLIENT_PREFIX_12, GRPC_DTS_CLIENT_PREFIX_13, GRPC_DTS_CLIENT_PREFIX_14, GRPC_DTS_CLIENT_PREFIX_15, GRPC_DTS_CLIENT_PREFIX_16, GRPC_DTS_CLIENT_PREFIX_17, GRPC_DTS_CLIENT_PREFIX_18, GRPC_DTS_CLIENT_PREFIX_19, GRPC_DTS_CLIENT_PREFIX_20, GRPC_DTS_CLIENT_PREFIX_21, GRPC_DTS_CLIENT_PREFIX_22, GRPC_DTS_CLIENT_PREFIX_23, /* frame header byte 0... */ /* must follow from the prefix states */ GRPC_DTS_FH_0, GRPC_DTS_FH_1, GRPC_DTS_FH_2, GRPC_DTS_FH_3, GRPC_DTS_FH_4, GRPC_DTS_FH_5, GRPC_DTS_FH_6, GRPC_DTS_FH_7, /* ... frame header byte 8 */ GRPC_DTS_FH_8, /* inside a http2 frame */ GRPC_DTS_FRAME } grpc_chttp2_deframe_transport_state; typedef enum { GRPC_WRITE_STATE_OPEN, GRPC_WRITE_STATE_QUEUED_CLOSE, GRPC_WRITE_STATE_SENT_CLOSE } grpc_chttp2_write_state; /* flags that can be or'd into stream_global::writing_now */ #define GRPC_CHTTP2_WRITING_DATA 1 #define GRPC_CHTTP2_WRITING_WINDOW 2 typedef enum { GRPC_DONT_SEND_CLOSED = 0, GRPC_SEND_CLOSED, GRPC_SEND_CLOSED_WITH_RST_STREAM } grpc_chttp2_send_closed; typedef struct { grpc_chttp2_stream *head; grpc_chttp2_stream *tail; } grpc_chttp2_stream_list; typedef struct { grpc_chttp2_stream *next; grpc_chttp2_stream *prev; } grpc_chttp2_stream_link; /* We keep several sets of connection wide parameters */ typedef enum { /* The settings our peer has asked for (and we have acked) */ GRPC_PEER_SETTINGS = 0, /* The settings we'd like to have */ GRPC_LOCAL_SETTINGS, /* The settings we've published to our peer */ GRPC_SENT_SETTINGS, /* The settings the peer has acked */ GRPC_ACKED_SETTINGS, GRPC_NUM_SETTING_SETS } grpc_chttp2_setting_set; /* Outstanding ping request data */ typedef struct grpc_chttp2_outstanding_ping { gpr_uint8 id[8]; grpc_iomgr_closure *on_recv; struct grpc_chttp2_outstanding_ping *next; struct grpc_chttp2_outstanding_ping *prev; } grpc_chttp2_outstanding_ping; typedef struct { /** data to write next write */ gpr_slice_buffer qbuf; /** queued callbacks */ grpc_iomgr_closure *pending_closures_head; grpc_iomgr_closure *pending_closures_tail; /** window available for us to send to peer */ gpr_uint32 outgoing_window; /** window available for peer to send to us - updated after parse */ gpr_uint32 incoming_window; /** how much window would we like to have for incoming_window */ gpr_uint32 connection_window_target; /** have we seen a goaway */ gpr_uint8 seen_goaway; /** have we sent a goaway */ gpr_uint8 sent_goaway; /** is this transport a client? */ gpr_uint8 is_client; /** are the local settings dirty and need to be sent? */ gpr_uint8 dirtied_local_settings; /** have local settings been sent? */ gpr_uint8 sent_local_settings; /** bitmask of setting indexes to send out */ gpr_uint32 force_send_settings; /** settings values */ gpr_uint32 settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS]; /** what is the next stream id to be allocated by this peer? copied to next_stream_id in parsing when parsing commences */ gpr_uint32 next_stream_id; /** last received stream id */ gpr_uint32 last_incoming_stream_id; /** pings awaiting responses */ grpc_chttp2_outstanding_ping pings; /** next payload for an outgoing ping */ gpr_uint64 ping_counter; /** concurrent stream count: updated when not parsing, so this is a strict over-estimation on the client */ gpr_uint32 concurrent_stream_count; } grpc_chttp2_transport_global; typedef struct { /** data to write now */ gpr_slice_buffer outbuf; /** hpack encoding */ grpc_chttp2_hpack_compressor hpack_compressor; /** is this a client? */ gpr_uint8 is_client; /** callback for when writing is done */ grpc_iomgr_closure done_cb; } grpc_chttp2_transport_writing; struct grpc_chttp2_transport_parsing { /** is this transport a client? (boolean) */ gpr_uint8 is_client; /** were settings updated? */ gpr_uint8 settings_updated; /** was a settings ack received? */ gpr_uint8 settings_ack_received; /** was a goaway frame received? */ gpr_uint8 goaway_received; /** initial window change */ gpr_int64 initial_window_update; /** data to write later - after parsing */ gpr_slice_buffer qbuf; /* metadata object cache */ grpc_mdstr *str_grpc_timeout; /** parser for headers */ grpc_chttp2_hpack_parser hpack_parser; /** simple one shot parsers */ union { grpc_chttp2_window_update_parser window_update; grpc_chttp2_settings_parser settings; grpc_chttp2_ping_parser ping; grpc_chttp2_rst_stream_parser rst_stream; } simple; /** parser for goaway frames */ grpc_chttp2_goaway_parser goaway_parser; /** window available for peer to send to us */ gpr_uint32 incoming_window; gpr_uint32 incoming_window_delta; /** next stream id available at the time of beginning parsing */ gpr_uint32 next_stream_id; gpr_uint32 last_incoming_stream_id; /* deframing */ grpc_chttp2_deframe_transport_state deframe_state; gpr_uint8 incoming_frame_type; gpr_uint8 incoming_frame_flags; gpr_uint8 header_eof; gpr_uint32 expect_continuation_stream_id; gpr_uint32 incoming_frame_size; gpr_uint32 incoming_stream_id; /* active parser */ void *parser_data; grpc_chttp2_stream_parsing *incoming_stream; grpc_chttp2_parse_error (*parser)( void *parser_user_data, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); /* received settings */ gpr_uint32 settings[GRPC_CHTTP2_NUM_SETTINGS]; /* goaway data */ grpc_status_code goaway_error; gpr_uint32 goaway_last_stream_index; gpr_slice goaway_text; gpr_uint64 outgoing_window_update; /** pings awaiting responses */ grpc_chttp2_outstanding_ping pings; }; struct grpc_chttp2_transport { grpc_transport base; /* must be first */ grpc_endpoint *ep; grpc_mdctx *metadata_context; gpr_refcount refs; char *peer_string; /** when this drops to zero it's safe to shutdown the endpoint */ gpr_refcount shutdown_ep_refs; gpr_mu mu; /** is the transport destroying itself? */ gpr_uint8 destroying; /** has the upper layer closed the transport? */ gpr_uint8 closed; /** is a thread currently writing */ gpr_uint8 writing_active; /** is a thread currently parsing */ gpr_uint8 parsing_active; /** is there a read request to the endpoint outstanding? */ gpr_uint8 endpoint_reading; /** various lists of streams */ grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; /** global state for reading/writing */ grpc_chttp2_transport_global global; /** state only accessible by the chain of execution that set writing_active=1 */ grpc_chttp2_transport_writing writing; /** state only accessible by the chain of execution that set parsing_active=1 */ grpc_chttp2_transport_parsing parsing; /** maps stream id to grpc_chttp2_stream objects; owned by the parsing thread when parsing */ grpc_chttp2_stream_map parsing_stream_map; /** streams created by the client (possibly during parsing); merged with parsing_stream_map during unlock when no parsing is occurring */ grpc_chttp2_stream_map new_stream_map; /** closure to execute writing */ grpc_iomgr_closure writing_action; /** closure to finish reading from the endpoint */ grpc_iomgr_closure recv_data; /** incoming read bytes */ gpr_slice_buffer read_buffer; /** address to place a newly accepted stream - set and unset by grpc_chttp2_parsing_accept_stream; used by init_stream to publish the accepted server stream */ grpc_chttp2_stream **accepting_stream; struct { /* accept stream callback */ void (*accept_stream)(void *user_data, grpc_transport *transport, const void *server_data); void *accept_stream_user_data; /** connectivity tracking */ grpc_connectivity_state_tracker state_tracker; } channel_callback; }; typedef struct { /** HTTP2 stream id for this stream, or zero if one has not been assigned */ gpr_uint32 id; grpc_iomgr_closure *send_done_closure; grpc_iomgr_closure *recv_done_closure; /** window available for us to send to peer */ gpr_int64 outgoing_window; /** The number of bytes the upper layers have offered to receive. As the upper layer offers more bytes, this value increases. As bytes are read, this value decreases. */ gpr_uint32 max_recv_bytes; /** The number of bytes the upper layer has offered to read but we have not yet announced to HTTP2 flow control. As the upper layers offer to read more bytes, this value increases. As we advertise incoming flow control window, this value decreases. */ gpr_uint32 unannounced_incoming_window; /** The number of bytes of HTTP2 flow control we have advertised. As we advertise incoming flow control window, this value increases. As bytes are read, this value decreases. Updated after parse. */ gpr_uint32 incoming_window; /** stream ops the transport user would like to send */ grpc_stream_op_buffer *outgoing_sopb; /** when the application requests writes be closed, the write_closed is 'queued'; when the close is flow controlled into the send path, we are 'sending' it; when the write has been performed it is 'sent' */ grpc_chttp2_write_state write_state; /** is this stream closed (boolean) */ gpr_uint8 read_closed; /** has this stream been cancelled? (boolean) */ gpr_uint8 cancelled; grpc_status_code cancelled_status; /** have we told the upper layer that this stream is cancelled? */ gpr_uint8 published_cancelled; /** is this stream in the stream map? (boolean) */ gpr_uint8 in_stream_map; /** bitmask of GRPC_CHTTP2_WRITING_xxx above */ gpr_uint8 writing_now; /** has anything been written to this stream? */ gpr_uint8 written_anything; /** stream state already published to the upper layer */ grpc_stream_state published_state; /** address to publish next stream state to */ grpc_stream_state *publish_state; /** pointer to sop buffer to fill in with new stream ops */ grpc_stream_op_buffer *publish_sopb; grpc_stream_op_buffer incoming_sopb; /** incoming metadata */ grpc_chttp2_incoming_metadata_buffer incoming_metadata; grpc_chttp2_incoming_metadata_live_op_buffer outstanding_metadata; } grpc_chttp2_stream_global; typedef struct { /** HTTP2 stream id for this stream, or zero if one has not been assigned */ gpr_uint32 id; /** sops that have passed flow control to be written */ grpc_stream_op_buffer sopb; /** how strongly should we indicate closure with the next write */ grpc_chttp2_send_closed send_closed; /** how much window should we announce? */ gpr_uint32 announce_window; } grpc_chttp2_stream_writing; struct grpc_chttp2_stream_parsing { /** HTTP2 stream id for this stream, or zero if one has not been assigned */ gpr_uint32 id; /** has this stream received a close */ gpr_uint8 received_close; /** saw a rst_stream */ gpr_uint8 saw_rst_stream; /** incoming_window has been reduced by this much during parsing */ gpr_uint32 incoming_window_delta; /** window available for peer to send to us */ gpr_uint32 incoming_window; /** parsing state for data frames */ grpc_chttp2_data_parser data_parser; /** reason give to rst_stream */ gpr_uint32 rst_stream_reason; /* amount of window given */ gpr_uint64 outgoing_window_update; /** incoming metadata */ grpc_chttp2_incoming_metadata_buffer incoming_metadata; }; struct grpc_chttp2_stream { grpc_chttp2_stream_global global; grpc_chttp2_stream_writing writing; grpc_chttp2_stream_parsing parsing; grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; gpr_uint8 included[STREAM_LIST_COUNT]; }; /** Transport writing call flow: chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes are required; if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the writes. Once writes have been completed (meaning another write could potentially be started), grpc_chttp2_terminate_writing is called. This will call grpc_chttp2_cleanup_writing, at which point the write phase is complete. */ /** Someone is unlocking the transport mutex: check to see if writes are required, and schedule them if so */ int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global, grpc_chttp2_transport_writing *writing); void grpc_chttp2_perform_writes( grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint); void grpc_chttp2_terminate_writing(void *transport_writing, int success); void grpc_chttp2_cleanup_writing(grpc_chttp2_transport_global *global, grpc_chttp2_transport_writing *writing); void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global, grpc_chttp2_transport_parsing *parsing); /** Process one slice of incoming data; return 1 if the connection is still viable after reading, or 0 if the connection should be torn down */ int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing, gpr_slice slice); void grpc_chttp2_publish_reads(grpc_chttp2_transport_global *global, grpc_chttp2_transport_parsing *parsing); /** Get a writable stream returns non-zero if there was a stream available */ void grpc_chttp2_list_add_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); void grpc_chttp2_list_add_first_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_writing **stream_writing); void grpc_chttp2_list_remove_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); void grpc_chttp2_list_add_incoming_window_updated( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_incoming_window_updated( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_parsing **stream_parsing); void grpc_chttp2_list_remove_incoming_window_updated( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); void grpc_chttp2_list_add_writing_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing *stream_writing); int grpc_chttp2_list_have_writing_streams( grpc_chttp2_transport_writing *transport_writing); int grpc_chttp2_list_pop_writing_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing **stream_writing); void grpc_chttp2_list_add_written_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing *stream_writing); int grpc_chttp2_list_pop_written_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_writing **stream_writing); void grpc_chttp2_list_add_parsing_seen_stream( grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing); int grpc_chttp2_list_pop_parsing_seen_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_parsing **stream_parsing); void grpc_chttp2_list_add_waiting_for_concurrency( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_waiting_for_concurrency( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global); void grpc_chttp2_list_add_closed_waiting_for_parsing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_closed_waiting_for_parsing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global); void grpc_chttp2_list_add_cancelled_waiting_for_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_cancelled_waiting_for_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global); void grpc_chttp2_list_add_read_write_state_changed( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_read_write_state_changed( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global); /** schedule a closure to run without the transport lock taken */ void grpc_chttp2_schedule_closure( grpc_chttp2_transport_global *transport_global, grpc_iomgr_closure *closure, int success); grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id); grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id); void grpc_chttp2_add_incoming_goaway( grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error, gpr_slice goaway_text); void grpc_chttp2_register_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); /* returns 1 if this is the last stream, 0 otherwise */ int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; int grpc_chttp2_has_streams(grpc_chttp2_transport *t); void grpc_chttp2_for_all_streams( grpc_chttp2_transport_global *transport_global, void *user_data, void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, grpc_chttp2_stream_global *stream_global)); void grpc_chttp2_parsing_become_skip_parser( grpc_chttp2_transport_parsing *transport_parsing); #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1) extern int grpc_http_trace; extern int grpc_flowctl_trace; #define GRPC_CHTTP2_IF_TRACING(stmt) \ if (!(grpc_http_trace)) \ ; \ else \ stmt #define GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(reason, transport, context, var, \ delta) \ if (!(grpc_flowctl_trace)) { \ } else { \ grpc_chttp2_flowctl_trace(__FILE__, __LINE__, reason, #context, #var, \ transport->is_client, context->id, context->var, \ delta); \ } #define GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(reason, context, var, delta) \ if (!(grpc_flowctl_trace)) { \ } else { \ grpc_chttp2_flowctl_trace(__FILE__, __LINE__, reason, #context, #var, \ context->is_client, 0, context->var, delta); \ } void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason, const char *context, const char *var, int is_client, gpr_uint32 stream_id, gpr_int64 current_value, gpr_int64 delta); #endif grpc-0.11.1/src/core/transport/chttp2/incoming_metadata.h0000644000175000017500000000662412600663151023522 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H #define GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H #include "src/core/transport/transport.h" typedef struct { grpc_linked_mdelem *elems; size_t count; size_t capacity; gpr_timespec deadline; } grpc_chttp2_incoming_metadata_buffer; typedef struct { grpc_linked_mdelem *elems; } grpc_chttp2_incoming_metadata_live_op_buffer; /** assumes everything initially zeroed */ void grpc_chttp2_incoming_metadata_buffer_init( grpc_chttp2_incoming_metadata_buffer *buffer); void grpc_chttp2_incoming_metadata_buffer_destroy( grpc_chttp2_incoming_metadata_buffer *buffer); void grpc_chttp2_incoming_metadata_buffer_reset( grpc_chttp2_incoming_metadata_buffer *buffer); void grpc_chttp2_incoming_metadata_buffer_add( grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem); void grpc_chttp2_incoming_metadata_buffer_set_deadline( grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline); /** extend sopb with a metadata batch; this must be post-processed by grpc_chttp2_incoming_metadata_buffer_postprocess_sopb before being handed out of the transport */ void grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into( grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb); void grpc_incoming_metadata_buffer_move_to_referencing_sopb( grpc_chttp2_incoming_metadata_buffer *src, grpc_chttp2_incoming_metadata_buffer *dst, grpc_stream_op_buffer *sopb); void grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op( grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb, grpc_chttp2_incoming_metadata_live_op_buffer *live_op_buffer); void grpc_chttp2_incoming_metadata_live_op_buffer_end( grpc_chttp2_incoming_metadata_live_op_buffer *live_op_buffer); #endif /* GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H */ grpc-0.11.1/src/core/transport/chttp2/hpack_table.h0000644000175000017500000001010212600663151022276 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H #include "src/core/transport/metadata.h" #include #include /* HPACK header table */ /* last index in the static table */ #define GRPC_CHTTP2_LAST_STATIC_ENTRY 61 /* Initial table size as per the spec */ #define GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE 4096 /* Maximum table size that we'll use */ #define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE /* Per entry overhead bytes as per the spec */ #define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32 /* Maximum number of entries we could possibly fit in the table, given defined overheads */ #define GRPC_CHTTP2_MAX_TABLE_COUNT \ ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \ GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD) /* hpack decoder table */ typedef struct { grpc_mdctx *mdctx; /* the first used entry in ents */ gpr_uint16 first_ent; /* the last used entry in ents */ gpr_uint16 last_ent; /* how many entries are in the table */ gpr_uint16 num_ents; /* the amount of memory used by the table, according to the hpack algorithm */ gpr_uint16 mem_used; /* the max memory allowed to be used by the table, according to the hpack algorithm */ gpr_uint16 max_bytes; /* a circular buffer of headers - this is stored in the opposite order to what hpack specifies, in order to simplify table management a little... meaning lookups need to SUBTRACT from the end position */ grpc_mdelem *ents[GRPC_CHTTP2_MAX_TABLE_COUNT]; grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY]; } grpc_chttp2_hptbl; /* initialize a hpack table */ void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx); void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl); /* lookup a table entry based on its hpack index */ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, gpr_uint32 index); /* add a table entry to the index */ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md); /* Find a key/value pair in the table... returns the index in the table of the most similar entry, or 0 if the value was not found */ typedef struct { gpr_uint16 index; gpr_uint8 has_value; } grpc_chttp2_hptbl_find_result; grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( const grpc_chttp2_hptbl *tbl, grpc_mdelem *md); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H */ grpc-0.11.1/src/core/transport/chttp2/hpack_parser.c0000644000175000017500000020331112600663151022504 0ustar apollockapollock/* * * 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/transport/chttp2/hpack_parser.h" #include "src/core/transport/chttp2/internal.h" #include #include #include #include "src/core/transport/chttp2/bin_encoder.h" #include "src/core/support/string.h" #include #include #include #include typedef enum { NOT_BINARY, B64_BYTE0, B64_BYTE1, B64_BYTE2, B64_BYTE3 } binary_state; /* How parsing works: The parser object keeps track of a function pointer which represents the current parse state. Each time new bytes are presented, we call into the current state, which recursively parses until all bytes in the given chunk are exhausted. The parse state that terminates then saves its function pointer to be the current state so that it can resume when more bytes are available. It's expected that most optimizing compilers will turn this code into a set of indirect jumps, and so not waste stack space. */ /* forward declarations for parsing states */ static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_key_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value1(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value2(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value4(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_value5up(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); /* we translate the first byte of a hpack field into one of these decoding cases, then use a lookup table to jump directly to the appropriate parser. _X => the integer index is all ones, meaning we need to do varint decoding _V => the integer index is all zeros, meaning we need to decode an additional string value */ typedef enum { INDEXED_FIELD, INDEXED_FIELD_X, LITHDR_INCIDX, LITHDR_INCIDX_X, LITHDR_INCIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX_X, LITHDR_NOTIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX_X, LITHDR_NVRIDX_V, MAX_TBL_SIZE, MAX_TBL_SIZE_X, ILLEGAL } first_byte_type; /* jump table of parse state functions -- order must match first_byte_type above */ static const grpc_chttp2_hpack_parser_state first_byte_action[] = { parse_indexed_field, parse_indexed_field_x, parse_lithdr_incidx, parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx, parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx, parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size, parse_max_tbl_size_x, parse_error}; /* indexes the first byte to a parse state function - generated by gen_hpack_tables.c */ static const gpr_uint8 first_byte_lut[256] = { LITHDR_NOTIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX_X, LITHDR_NVRIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X, ILLEGAL, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE_X, LITHDR_INCIDX_V, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX_X, ILLEGAL, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD_X, }; /* state table for huffman decoding: given a state, gives an index/16 into next_sub_tbl. Taking that index and adding the value of the nibble being considered returns the next state. generated by gen_hpack_tables.c */ static const gpr_uint8 next_tbl[256] = { 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8, 1, 3, 3, 9, 10, 11, 1, 1, 1, 12, 1, 2, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 14, 1, 15, 16, 1, 17, 1, 15, 2, 7, 3, 18, 19, 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 7, 21, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 2, 2, 2, 2, 23, 24, 25, 1, 1, 1, 1, 2, 2, 2, 26, 3, 3, 27, 10, 28, 1, 1, 1, 1, 1, 1, 2, 3, 29, 10, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 32, 1, 1, 15, 33, 1, 34, 35, 9, 36, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 26, 9, 38, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 2, 2, 26, 3, 3, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 3, 3, 3, 40, 2, 41, 1, 1, 1, 42, 43, 1, 1, 44, 1, 1, 1, 1, 15, 2, 2, 2, 2, 2, 2, 3, 3, 3, 45, 46, 1, 1, 2, 2, 2, 35, 3, 3, 18, 47, 2, }; /* next state, based upon current state and the current nibble: see above. generated by gen_hpack_tables.c */ static const gpr_int16 next_sub_tbl[48 * 16] = { 1, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 2, 6, 10, 13, 14, 15, 16, 17, 2, 6, 10, 13, 14, 15, 16, 17, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 199, 200, 201, 202, 203, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 3, 7, 11, 24, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 132, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, 21, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 22, 23, 91, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 3, 7, 11, 24, 3, 7, 11, 24, 0, 0, 0, 0, 0, 41, 42, 43, 2, 6, 10, 13, 14, 15, 16, 17, 3, 7, 11, 24, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 44, 45, 2, 6, 10, 13, 14, 15, 16, 17, 46, 47, 48, 49, 50, 51, 52, 57, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 0, 0, 0, 0, 3, 7, 11, 24, 3, 7, 11, 24, 4, 8, 4, 8, 0, 0, 0, 92, 0, 0, 0, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 2, 6, 10, 13, 14, 15, 16, 17, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 148, 149, 150, 151, 3, 7, 11, 24, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 152, 153, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 154, 155, 156, 164, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 197, 198, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 219, 220, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 0, 0, 221, 222, 223, 224, 3, 7, 11, 24, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 225, 228, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, }; /* emission table: indexed like next_tbl, ultimately gives the byte to be emitted, or -1 for no byte, or 256 for end of stream generated by gen_hpack_tables.c */ static const gpr_uint16 emit_tbl[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 0, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, }; /* generated by gen_hpack_tables.c */ static const gpr_int16 emit_sub_tbl[249 * 16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 97, 97, 97, 97, 48, 48, 49, 49, 50, 50, 97, 97, 99, 99, 101, 101, 105, 105, 111, 111, 48, 49, 50, 97, 99, 101, 105, 111, 115, 116, -1, -1, -1, -1, -1, -1, 32, 32, 32, 32, 32, 32, 32, 32, 37, 37, 37, 37, 37, 37, 37, 37, 99, 99, 99, 99, 101, 101, 101, 101, 105, 105, 105, 105, 111, 111, 111, 111, 115, 115, 116, 116, 32, 37, 45, 46, 47, 51, 52, 53, 54, 55, 56, 57, 61, 61, 61, 61, 61, 61, 61, 61, 65, 65, 65, 65, 65, 65, 65, 65, 115, 115, 115, 115, 116, 116, 116, 116, 32, 32, 37, 37, 45, 45, 46, 46, 61, 65, 95, 98, 100, 102, 103, 104, 108, 109, 110, 112, 114, 117, -1, -1, 58, 58, 58, 58, 58, 58, 58, 58, 66, 66, 66, 66, 66, 66, 66, 66, 47, 47, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 61, 61, 65, 65, 95, 95, 98, 98, 100, 100, 102, 102, 103, 103, 104, 104, 108, 108, 109, 109, 110, 110, 112, 112, 114, 114, 117, 117, 58, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 106, 107, 113, 118, 119, 120, 121, 122, -1, -1, -1, -1, 38, 38, 38, 38, 38, 38, 38, 38, 42, 42, 42, 42, 42, 42, 42, 42, 44, 44, 44, 44, 44, 44, 44, 44, 59, 59, 59, 59, 59, 59, 59, 59, 88, 88, 88, 88, 88, 88, 88, 88, 90, 90, 90, 90, 90, 90, 90, 90, 33, 33, 34, 34, 40, 40, 41, 41, 63, 63, 39, 43, 124, -1, -1, -1, 35, 35, 35, 35, 35, 35, 35, 35, 62, 62, 62, 62, 62, 62, 62, 62, 0, 0, 0, 0, 36, 36, 36, 36, 64, 64, 64, 64, 91, 91, 91, 91, 69, 69, 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 89, 89, 89, 89, 89, 89, 89, 89, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, 107, 107, 107, 107, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 122, 122, 122, 122, 122, 122, 122, 122, 38, 38, 38, 38, 42, 42, 42, 42, 44, 44, 44, 44, 59, 59, 59, 59, 88, 88, 88, 88, 90, 90, 90, 90, 33, 34, 40, 41, 63, -1, -1, -1, 39, 39, 39, 39, 39, 39, 39, 39, 43, 43, 43, 43, 43, 43, 43, 43, 124, 124, 124, 124, 124, 124, 124, 124, 35, 35, 35, 35, 62, 62, 62, 62, 0, 0, 36, 36, 64, 64, 91, 91, 93, 93, 126, 126, 94, 125, -1, -1, 60, 60, 60, 60, 60, 60, 60, 60, 96, 96, 96, 96, 96, 96, 96, 96, 123, 123, 123, 123, 123, 123, 123, 123, -1, -1, -1, -1, -1, -1, -1, -1, 92, 92, 92, 92, 92, 92, 92, 92, 195, 195, 195, 195, 195, 195, 195, 195, 208, 208, 208, 208, 208, 208, 208, 208, 128, 128, 128, 128, 130, 130, 130, 130, 131, 131, 131, 131, 162, 162, 162, 162, 184, 184, 184, 184, 194, 194, 194, 194, 224, 224, 224, 224, 226, 226, 226, 226, 153, 153, 161, 161, 167, 167, 172, 172, 176, 176, 177, 177, 179, 179, 209, 209, 216, 216, 217, 217, 227, 227, 229, 229, 230, 230, 129, 132, 133, 134, 136, 146, 154, 156, 160, 163, 164, 169, 170, 173, 178, 181, 185, 186, 187, 189, 190, 196, 198, 228, 232, 233, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 135, 135, 135, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 137, 137, 137, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141, 141, 141, 143, 143, 143, 143, 143, 143, 143, 143, 147, 147, 147, 147, 147, 147, 147, 147, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152, 152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 157, 157, 157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 165, 165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166, 168, 168, 168, 168, 168, 168, 168, 168, 174, 174, 174, 174, 174, 174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 175, 180, 180, 180, 180, 180, 180, 180, 180, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183, 183, 183, 183, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191, 191, 191, 191, 191, 197, 197, 197, 197, 197, 197, 197, 197, 231, 231, 231, 231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 9, 9, 9, 9, 142, 142, 142, 142, 144, 144, 144, 144, 145, 145, 145, 145, 148, 148, 148, 148, 159, 159, 159, 159, 171, 171, 171, 171, 206, 206, 206, 206, 215, 215, 215, 215, 225, 225, 225, 225, 236, 236, 236, 236, 237, 237, 237, 237, 199, 199, 207, 207, 234, 234, 235, 235, 192, 193, 200, 201, 202, 205, 210, 213, 218, 219, 238, 240, 242, 243, 255, -1, 203, 203, 203, 203, 203, 203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 211, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 214, 214, 214, 214, 214, 214, 214, 214, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 241, 241, 241, 241, 241, 241, 241, 241, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 11, 11, 11, 11, 12, 12, 12, 12, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 127, 127, 127, 127, 220, 220, 220, 220, 249, 249, 249, 249, 10, 13, 22, 256, 93, 93, 93, 93, 126, 126, 126, 126, 94, 94, 125, 125, 60, 96, 123, -1, 92, 195, 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, 128, 128, 128, 128, 128, 128, 128, 130, 130, 130, 130, 130, 130, 130, 130, 131, 131, 131, 131, 131, 131, 131, 131, 162, 162, 162, 162, 162, 162, 162, 162, 184, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 194, 194, 194, 224, 224, 224, 224, 224, 224, 224, 224, 226, 226, 226, 226, 226, 226, 226, 226, 153, 153, 153, 153, 161, 161, 161, 161, 167, 167, 167, 167, 172, 172, 172, 172, 176, 176, 176, 176, 177, 177, 177, 177, 179, 179, 179, 179, 209, 209, 209, 209, 216, 216, 216, 216, 217, 217, 217, 217, 227, 227, 227, 227, 229, 229, 229, 229, 230, 230, 230, 230, 129, 129, 132, 132, 133, 133, 134, 134, 136, 136, 146, 146, 154, 154, 156, 156, 160, 160, 163, 163, 164, 164, 169, 169, 170, 170, 173, 173, 178, 178, 181, 181, 185, 185, 186, 186, 187, 187, 189, 189, 190, 190, 196, 196, 198, 198, 228, 228, 232, 232, 233, 233, 1, 135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152, 155, 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231, 239, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, 9, 9, 9, 9, 9, 9, 142, 142, 142, 142, 142, 142, 142, 142, 144, 144, 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 148, 148, 148, 148, 148, 148, 148, 148, 159, 159, 159, 159, 159, 159, 159, 159, 171, 171, 171, 171, 171, 171, 171, 171, 206, 206, 206, 206, 206, 206, 206, 206, 215, 215, 215, 215, 215, 215, 215, 215, 225, 225, 225, 225, 225, 225, 225, 225, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 199, 199, 199, 199, 207, 207, 207, 207, 234, 234, 234, 234, 235, 235, 235, 235, 192, 192, 193, 193, 200, 200, 201, 201, 202, 202, 205, 205, 210, 210, 213, 213, 218, 218, 219, 219, 238, 238, 240, 240, 242, 242, 243, 243, 255, 255, 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245, 246, 247, 248, 250, 251, 252, 253, 254, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 127, 127, 127, 127, 127, 127, 127, 127, 220, 220, 220, 220, 220, 220, 220, 220, 249, 249, 249, 249, 249, 249, 249, 249, 10, 10, 13, 13, 22, 22, 256, 256, 67, 67, 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 95, 95, 95, 95, 95, 95, 95, 95, 98, 98, 98, 98, 98, 98, 98, 98, 100, 100, 100, 100, 100, 100, 100, 100, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 108, 108, 108, 108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110, 110, 110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 112, 112, 114, 114, 114, 114, 114, 114, 114, 114, 117, 117, 117, 117, 117, 117, 117, 117, 58, 58, 58, 58, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 89, 89, 89, 89, 106, 106, 106, 106, 107, 107, 107, 107, 113, 113, 113, 113, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 38, 38, 42, 42, 44, 44, 59, 59, 88, 88, 90, 90, -1, -1, -1, -1, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 63, 63, 63, 63, 63, 63, 63, 63, 39, 39, 39, 39, 43, 43, 43, 43, 124, 124, 124, 124, 35, 35, 62, 62, 0, 36, 64, 91, 93, 126, -1, -1, 94, 94, 94, 94, 94, 94, 94, 94, 125, 125, 125, 125, 125, 125, 125, 125, 60, 60, 60, 60, 96, 96, 96, 96, 123, 123, 123, 123, -1, -1, -1, -1, 92, 92, 92, 92, 195, 195, 195, 195, 208, 208, 208, 208, 128, 128, 130, 130, 131, 131, 162, 162, 184, 184, 194, 194, 224, 224, 226, 226, 153, 161, 167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230, -1, -1, -1, -1, -1, -1, -1, 129, 129, 129, 129, 129, 129, 129, 129, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, 134, 134, 134, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146, 146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 156, 156, 156, 156, 156, 156, 156, 156, 160, 160, 160, 160, 160, 160, 160, 160, 163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, 164, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, 173, 173, 173, 173, 173, 173, 173, 173, 178, 178, 178, 178, 178, 178, 178, 178, 181, 181, 181, 181, 181, 181, 181, 181, 185, 185, 185, 185, 185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187, 187, 187, 187, 187, 187, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190, 190, 190, 190, 190, 190, 190, 196, 196, 196, 196, 196, 196, 196, 196, 198, 198, 198, 198, 198, 198, 198, 198, 228, 228, 228, 228, 228, 228, 228, 228, 232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 1, 1, 1, 1, 135, 135, 135, 135, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 143, 143, 143, 143, 147, 147, 147, 147, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 155, 155, 155, 155, 157, 157, 157, 157, 158, 158, 158, 158, 165, 165, 165, 165, 166, 166, 166, 166, 168, 168, 168, 168, 174, 174, 174, 174, 175, 175, 175, 175, 180, 180, 180, 180, 182, 182, 182, 182, 183, 183, 183, 183, 188, 188, 188, 188, 191, 191, 191, 191, 197, 197, 197, 197, 231, 231, 231, 231, 239, 239, 239, 239, 9, 9, 142, 142, 144, 144, 145, 145, 148, 148, 159, 159, 171, 171, 206, 206, 215, 215, 225, 225, 236, 236, 237, 237, 199, 207, 234, 235, 192, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 200, 200, 200, 200, 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202, 202, 202, 202, 202, 202, 205, 205, 205, 205, 205, 205, 205, 205, 210, 210, 210, 210, 210, 210, 210, 210, 213, 213, 213, 213, 213, 213, 213, 213, 218, 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 219, 238, 238, 238, 238, 238, 238, 238, 238, 240, 240, 240, 240, 240, 240, 240, 240, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, 243, 243, 255, 255, 255, 255, 255, 255, 255, 255, 203, 203, 203, 203, 204, 204, 204, 204, 211, 211, 211, 211, 212, 212, 212, 212, 214, 214, 214, 214, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 241, 241, 241, 241, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 11, 11, 12, 12, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 127, 127, 220, 220, 249, 249, -1, -1, 10, 10, 10, 10, 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13, 22, 22, 22, 22, 22, 22, 22, 22, 256, 256, 256, 256, 256, 256, 256, 256, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 50, 50, 50, 50, 50, 50, 50, 50, 97, 97, 97, 97, 97, 97, 97, 97, 99, 99, 99, 99, 99, 99, 99, 99, 101, 101, 101, 101, 101, 101, 101, 101, 105, 105, 105, 105, 105, 105, 105, 105, 111, 111, 111, 111, 111, 111, 111, 111, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 116, 116, 116, 116, 116, 116, 32, 32, 32, 32, 37, 37, 37, 37, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 61, 61, 61, 61, 65, 65, 65, 65, 95, 95, 95, 95, 98, 98, 98, 98, 100, 100, 100, 100, 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 112, 112, 112, 112, 114, 114, 114, 114, 117, 117, 117, 117, 58, 58, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 89, 89, 106, 106, 107, 107, 113, 113, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 38, 42, 44, 59, 88, 90, -1, -1, 33, 33, 33, 33, 34, 34, 34, 34, 40, 40, 40, 40, 41, 41, 41, 41, 63, 63, 63, 63, 39, 39, 43, 43, 124, 124, 35, 62, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 36, 36, 64, 64, 64, 64, 64, 64, 64, 64, 91, 91, 91, 91, 91, 91, 91, 91, 93, 93, 93, 93, 93, 93, 93, 93, 126, 126, 126, 126, 126, 126, 126, 126, 94, 94, 94, 94, 125, 125, 125, 125, 60, 60, 96, 96, 123, 123, -1, -1, 92, 92, 195, 195, 208, 208, 128, 130, 131, 162, 184, 194, 224, 226, -1, -1, 153, 153, 153, 153, 153, 153, 153, 153, 161, 161, 161, 161, 161, 161, 161, 161, 167, 167, 167, 167, 167, 167, 167, 167, 172, 172, 172, 172, 172, 172, 172, 172, 176, 176, 176, 176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179, 179, 179, 179, 179, 179, 179, 209, 209, 209, 209, 209, 209, 209, 209, 216, 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217, 227, 227, 227, 227, 227, 227, 227, 227, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 230, 230, 230, 230, 230, 129, 129, 129, 129, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 136, 136, 136, 136, 146, 146, 146, 146, 154, 154, 154, 154, 156, 156, 156, 156, 160, 160, 160, 160, 163, 163, 163, 163, 164, 164, 164, 164, 169, 169, 169, 169, 170, 170, 170, 170, 173, 173, 173, 173, 178, 178, 178, 178, 181, 181, 181, 181, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 189, 189, 189, 189, 190, 190, 190, 190, 196, 196, 196, 196, 198, 198, 198, 198, 228, 228, 228, 228, 232, 232, 232, 232, 233, 233, 233, 233, 1, 1, 135, 135, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 143, 143, 147, 147, 149, 149, 150, 150, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 165, 165, 166, 166, 168, 168, 174, 174, 175, 175, 180, 180, 182, 182, 183, 183, 188, 188, 191, 191, 197, 197, 231, 231, 239, 239, 9, 142, 144, 145, 148, 159, 171, 206, 215, 225, 236, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 199, 199, 199, 199, 199, 199, 199, 199, 207, 207, 207, 207, 207, 207, 207, 207, 234, 234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, 192, 192, 192, 192, 193, 193, 193, 193, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 205, 205, 205, 205, 210, 210, 210, 210, 213, 213, 213, 213, 218, 218, 218, 218, 219, 219, 219, 219, 238, 238, 238, 238, 240, 240, 240, 240, 242, 242, 242, 242, 243, 243, 243, 243, 255, 255, 255, 255, 203, 203, 204, 204, 211, 211, 212, 212, 214, 214, 221, 221, 222, 222, 223, 223, 241, 241, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 2, 3, 4, 5, 6, 7, 8, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 220, 249, -1, 10, 10, 10, 10, 13, 13, 13, 13, 22, 22, 22, 22, 256, 256, 256, 256, }; static const gpr_uint8 inverse_base64[256] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; /* emission helpers */ static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, int add_to_table) { if (add_to_table) { GRPC_MDELEM_REF(md); grpc_chttp2_hptbl_add(&p->table, md); } p->on_header(p->on_header_user_data, md); } static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p, grpc_chttp2_hpack_parser_string *str) { grpc_mdstr *s = grpc_mdstr_from_buffer(p->table.mdctx, (gpr_uint8 *)str->str, str->length); str->length = 0; return s; } /* jump to the next state */ static int parse_next(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { p->state = *p->next_state++; return p->state(p, cur, end); } /* begin parsing a header: all functionality is encoded into lookup tables above */ static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_begin; return 1; } return first_byte_action[first_byte_lut[*cur]](p, cur, end); } /* stream dependency and prioritization data: we just skip it */ static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_stream_weight; return 1; } return p->after_prioritization(p, cur + 1, end); } static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_stream_dep3; return 1; } return parse_stream_weight(p, cur + 1, end); } static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_stream_dep2; return 1; } return parse_stream_dep3(p, cur + 1, end); } static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_stream_dep1; return 1; } return parse_stream_dep2(p, cur + 1, end); } static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_stream_dep0; return 1; } return parse_stream_dep1(p, cur + 1, end); } /* emit an indexed field; for now just logs it to console; jumps to begin the next field on completion */ static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); GRPC_MDELEM_REF(md); on_hdr(p, md, 0); return parse_begin(p, cur, end); } /* parse an indexed field with index < 127 */ static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { p->index = (*cur) & 0x7f; return finish_indexed_field(p, cur + 1, end); } /* parse an indexed field with index >= 127 */ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { finish_indexed_field}; p->next_state = and_then; p->index = 0x7f; p->parsing.value = &p->index; return parse_value0(p, cur + 1, end); } /* finish a literal header with incremental indexing: just log, and jump to ' begin */ static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, GRPC_MDSTR_REF(md->key), take_string(p, &p->value)), 1); return parse_begin(p, cur, end); } /* finish a literal header with incremental indexing with no index */ static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, take_string(p, &p->key), take_string(p, &p->value)), 1); return parse_begin(p, cur, end); } /* parse a literal header with incremental indexing; index < 63 */ static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_value_string_with_indexed_key, finish_lithdr_incidx}; p->next_state = and_then; p->index = (*cur) & 0x3f; return parse_string_prefix(p, cur + 1, end); } /* parse a literal header with incremental indexing; index >= 63 */ static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_string_prefix, parse_value_string_with_indexed_key, finish_lithdr_incidx}; p->next_state = and_then; p->index = 0x3f; p->parsing.value = &p->index; return parse_value0(p, cur + 1, end); } /* parse a literal header with incremental indexing; index = 0 */ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_key_string, parse_string_prefix, parse_value_string_with_literal_key, finish_lithdr_incidx_v}; p->next_state = and_then; return parse_string_prefix(p, cur + 1, end); } /* finish a literal header without incremental indexing */ static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, GRPC_MDSTR_REF(md->key), take_string(p, &p->value)), 0); return parse_begin(p, cur, end); } /* finish a literal header without incremental indexing with index = 0 */ static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, take_string(p, &p->key), take_string(p, &p->value)), 0); return parse_begin(p, cur, end); } /* parse a literal header without incremental indexing; index < 15 */ static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_value_string_with_indexed_key, finish_lithdr_notidx}; p->next_state = and_then; p->index = (*cur) & 0xf; return parse_string_prefix(p, cur + 1, end); } /* parse a literal header without incremental indexing; index >= 15 */ static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_string_prefix, parse_value_string_with_indexed_key, finish_lithdr_notidx}; p->next_state = and_then; p->index = 0xf; p->parsing.value = &p->index; return parse_value0(p, cur + 1, end); } /* parse a literal header without incremental indexing; index == 0 */ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_key_string, parse_string_prefix, parse_value_string_with_literal_key, finish_lithdr_notidx_v}; p->next_state = and_then; return parse_string_prefix(p, cur + 1, end); } /* finish a literal header that is never indexed */ static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, GRPC_MDSTR_REF(md->key), take_string(p, &p->value)), 0); return parse_begin(p, cur, end); } /* finish a literal header that is never indexed with an extra value */ static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, take_string(p, &p->key), take_string(p, &p->value)), 0); return parse_begin(p, cur, end); } /* parse a literal header that is never indexed; index < 15 */ static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_value_string_with_indexed_key, finish_lithdr_nvridx}; p->next_state = and_then; p->index = (*cur) & 0xf; return parse_string_prefix(p, cur + 1, end); } /* parse a literal header that is never indexed; index >= 15 */ static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_string_prefix, parse_value_string_with_indexed_key, finish_lithdr_nvridx}; p->next_state = and_then; p->index = 0xf; p->parsing.value = &p->index; return parse_value0(p, cur + 1, end); } /* parse a literal header that is never indexed; index == 0 */ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_key_string, parse_string_prefix, parse_value_string_with_literal_key, finish_lithdr_nvridx_v}; p->next_state = and_then; return parse_string_prefix(p, cur + 1, end); } /* finish parsing a max table size change */ static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); abort(); /* not implemented */ return parse_begin(p, cur, end); } /* parse a max table size change, max size < 15 */ static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { p->index = (*cur) & 0xf; return finish_max_tbl_size(p, cur + 1, end); } /* parse a max table size change, max size >= 15 */ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { finish_max_tbl_size}; p->next_state = and_then; p->index = 0xf; p->parsing.value = &p->index; return parse_value0(p, cur + 1, end); } /* a parse error: jam the parse state into parse_error, and return error */ static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { p->state = parse_error; return 0; } /* parse the 1st byte of a varint into p->parsing.value no overflow is possible */ static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_value0; return 1; } *p->parsing.value += (*cur) & 0x7f; if ((*cur) & 0x80) { return parse_value1(p, cur + 1, end); } else { return parse_next(p, cur + 1, end); } } /* parse the 2nd byte of a varint into p->parsing.value no overflow is possible */ static int parse_value1(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_value1; return 1; } *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 7; if ((*cur) & 0x80) { return parse_value2(p, cur + 1, end); } else { return parse_next(p, cur + 1, end); } } /* parse the 3rd byte of a varint into p->parsing.value no overflow is possible */ static int parse_value2(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_value2; return 1; } *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 14; if ((*cur) & 0x80) { return parse_value3(p, cur + 1, end); } else { return parse_next(p, cur + 1, end); } } /* parse the 4th byte of a varint into p->parsing.value no overflow is possible */ static int parse_value3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_value3; return 1; } *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 21; if ((*cur) & 0x80) { return parse_value4(p, cur + 1, end); } else { return parse_next(p, cur + 1, end); } } /* parse the 5th byte of a varint into p->parsing.value depending on the byte, we may overflow, and care must be taken */ static int parse_value4(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { gpr_uint8 c; gpr_uint32 cur_value; gpr_uint32 add_value; if (cur == end) { p->state = parse_value4; return 1; } c = (*cur) & 0x7f; if (c > 0xf) { goto error; } cur_value = *p->parsing.value; add_value = ((gpr_uint32)c) << 28; if (add_value > 0xffffffffu - cur_value) { goto error; } *p->parsing.value = cur_value + add_value; if ((*cur) & 0x80) { return parse_value5up(p, cur + 1, end); } else { return parse_next(p, cur + 1, end); } error: gpr_log(GPR_ERROR, "integer overflow in hpack integer decoding: have 0x%08x, " "got byte 0x%02x", *p->parsing.value, *cur); return parse_error(p, cur, end); } /* parse any trailing bytes in a varint: it's possible to append an arbitrary number of 0x80's and not affect the value - a zero will terminate - and anything else will overflow */ static int parse_value5up(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { while (cur != end && *cur == 0x80) { ++cur; } if (cur == end) { p->state = parse_value5up; return 1; } if (*cur == 0) { return parse_next(p, cur + 1, end); } gpr_log(GPR_ERROR, "integer overflow in hpack integer decoding: have 0x%08x, " "got byte 0x%02x sometime after byte 4"); return parse_error(p, cur, end); } /* parse a string prefix */ static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (cur == end) { p->state = parse_string_prefix; return 1; } p->strlen = (*cur) & 0x7f; p->huff = (*cur) >> 7; if (p->strlen == 0x7f) { p->parsing.value = &p->strlen; return parse_value0(p, cur + 1, end); } else { return parse_next(p, cur + 1, end); } } /* append some bytes to a string */ static void append_bytes(grpc_chttp2_hpack_parser_string *str, const gpr_uint8 *data, size_t length) { if (length + str->length > str->capacity) { str->capacity = str->length + length; str->str = gpr_realloc(str->str, str->capacity); } memcpy(str->str + str->length, data, length); str->length += length; } static int append_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_chttp2_hpack_parser_string *str = p->parsing.str; gpr_uint32 bits; gpr_uint8 decoded[3]; switch ((binary_state)p->binary) { case NOT_BINARY: append_bytes(str, cur, end - cur); return 1; b64_byte0: case B64_BYTE0: if (cur == end) { p->binary = B64_BYTE0; return 1; } bits = inverse_base64[*cur]; ++cur; if (bits == 255) return 0; else if (bits == 64) goto b64_byte0; p->base64_buffer = bits << 18; /* fallthrough */ b64_byte1: case B64_BYTE1: if (cur == end) { p->binary = B64_BYTE1; return 1; } bits = inverse_base64[*cur]; ++cur; if (bits == 255) return 0; else if (bits == 64) goto b64_byte1; p->base64_buffer |= bits << 12; /* fallthrough */ b64_byte2: case B64_BYTE2: if (cur == end) { p->binary = B64_BYTE2; return 1; } bits = inverse_base64[*cur]; ++cur; if (bits == 255) return 0; else if (bits == 64) goto b64_byte2; p->base64_buffer |= bits << 6; /* fallthrough */ b64_byte3: case B64_BYTE3: if (cur == end) { p->binary = B64_BYTE3; return 1; } bits = inverse_base64[*cur]; ++cur; if (bits == 255) return 0; else if (bits == 64) goto b64_byte3; p->base64_buffer |= bits; bits = p->base64_buffer; decoded[0] = bits >> 16; decoded[1] = bits >> 8; decoded[2] = bits; append_bytes(str, decoded, 3); goto b64_byte0; } gpr_log(GPR_ERROR, "should never reach here"); abort(); return 1; } /* append a null terminator to a string */ static int finish_str(grpc_chttp2_hpack_parser *p) { gpr_uint8 terminator = 0; gpr_uint8 decoded[2]; gpr_uint32 bits; grpc_chttp2_hpack_parser_string *str = p->parsing.str; switch ((binary_state)p->binary) { case NOT_BINARY: break; case B64_BYTE0: break; case B64_BYTE1: gpr_log(GPR_ERROR, "illegal base64 encoding"); return 0; /* illegal encoding */ case B64_BYTE2: bits = p->base64_buffer; if (bits & 0xffff) { gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x", bits & 0xffff); return 0; } decoded[0] = bits >> 16; append_bytes(str, decoded, 1); break; case B64_BYTE3: bits = p->base64_buffer; if (bits & 0xff) { gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x", bits & 0xff); return 0; } decoded[0] = bits >> 16; decoded[1] = bits >> 8; append_bytes(str, decoded, 2); break; } append_bytes(str, &terminator, 1); p->parsing.str->length--; /* don't actually count the null terminator */ return 1; } /* decode a nibble from a huffman encoded stream */ static int huff_nibble(grpc_chttp2_hpack_parser *p, gpr_uint8 nibble) { gpr_int16 emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble]; gpr_int16 next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble]; if (emit != -1) { if (emit >= 0 && emit < 256) { gpr_uint8 c = (gpr_uint8)emit; if (!append_string(p, &c, (&c) + 1)) return 0; } else { assert(emit == 256); } } p->huff_state = next; return 1; } /* decode full bytes from a huffman encoded stream */ static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { for (; cur != end; ++cur) { if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0; } return 1; } /* decode some string bytes based on the current decoding mode (huffman or not) */ static int add_str_bytes(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { if (p->huff) { return add_huff_bytes(p, cur, end); } else { return append_string(p, cur, end); } } /* parse a string - tries to do large chunks at a time */ static int parse_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { size_t remaining = p->strlen - p->strgot; size_t given = end - cur; if (remaining <= given) { return add_str_bytes(p, cur, cur + remaining) && finish_str(p) && parse_next(p, cur + remaining, end); } else { if (!add_str_bytes(p, cur, cur + given)) return 0; p->strgot += given; p->state = parse_string; return 1; } } /* begin parsing a string - performs setup, calls parse_string */ static int begin_parse_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end, gpr_uint8 binary, grpc_chttp2_hpack_parser_string *str) { p->strgot = 0; str->length = 0; p->parsing.str = str; p->huff_state = 0; p->binary = binary; return parse_string(p, cur, end); } /* parse the key string */ static int parse_key_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { return begin_parse_string(p, cur, end, NOT_BINARY, &p->key); } /* check if a key represents a binary header or not */ typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header; static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) { return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER : PLAINTEXT_HEADER; } static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) { grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index); if (!elem) return ERROR_HEADER; return grpc_is_binary_header( (const char *)GPR_SLICE_START_PTR(elem->key->slice), GPR_SLICE_LENGTH(elem->key->slice)) ? BINARY_HEADER : PLAINTEXT_HEADER; } /* parse the value string */ static int parse_value_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end, is_binary_header type) { switch (type) { case BINARY_HEADER: return begin_parse_string(p, cur, end, B64_BYTE0, &p->value); case PLAINTEXT_HEADER: return begin_parse_string(p, cur, end, NOT_BINARY, &p->value); case ERROR_HEADER: return 0; } /* Add code to prevent return without value error */ gpr_log(GPR_ERROR, "Should never reach beyond switch in parse_value_string"); abort(); return 0; } static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { return parse_value_string(p, cur, end, is_binary_indexed_header(p)); } static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { return parse_value_string(p, cur, end, is_binary_literal_header(p)); } /* PUBLIC INTERFACE */ static void on_header_not_set(void *user_data, grpc_mdelem *md) { char *keyhex = gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); char *valuehex = gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_ERROR, "on_header callback not set; key=%s value=%s", keyhex, valuehex); gpr_free(keyhex); gpr_free(valuehex); GRPC_MDELEM_UNREF(md); abort(); } void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p, grpc_mdctx *mdctx) { p->on_header = on_header_not_set; p->on_header_user_data = NULL; p->state = parse_begin; p->key.str = NULL; p->key.capacity = 0; p->key.length = 0; p->value.str = NULL; p->value.capacity = 0; p->value.length = 0; grpc_chttp2_hptbl_init(&p->table, mdctx); } void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) { p->after_prioritization = p->state; p->state = parse_stream_dep0; } void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) { grpc_chttp2_hptbl_destroy(&p->table); gpr_free(p->key.str); gpr_free(p->value.str); } int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, const gpr_uint8 *beg, const gpr_uint8 *end) { /* TODO(ctiller): limit the distance of end from beg, and perform multiple steps in the event of a large chunk of data to limit stack space usage when no tail call optimization is available */ return p->state(p, beg, end); } grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( void *hpack_parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_hpack_parser *parser = hpack_parser; if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice))) { return GRPC_CHTTP2_CONNECTION_ERROR; } if (is_last) { if (parser->is_boundary && parser->state != parse_begin) { gpr_log(GPR_ERROR, "end of header frame not aligned with a hpack record boundary"); return GRPC_CHTTP2_CONNECTION_ERROR; } if (parser->is_boundary) { grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into( &stream_parsing->incoming_metadata, &stream_parsing->data_parser.incoming_sopb); grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } if (parser->is_eof) { stream_parsing->received_close = 1; } parser->on_header = on_header_not_set; parser->on_header_user_data = NULL; parser->is_boundary = 0xde; parser->is_eof = 0xde; } return GRPC_CHTTP2_PARSE_OK; } grpc-0.11.1/src/core/transport/chttp2/hpack_parser.h0000644000175000017500000001063712600663151022520 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H #include #include #include "src/core/transport/chttp2/frame.h" #include "src/core/transport/chttp2/hpack_table.h" #include "src/core/transport/metadata.h" typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser; typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p, const gpr_uint8 *beg, const gpr_uint8 *end); typedef struct { char *str; gpr_uint32 length; gpr_uint32 capacity; } grpc_chttp2_hpack_parser_string; struct grpc_chttp2_hpack_parser { /* user specified callback for each header output */ void (*on_header)(void *user_data, grpc_mdelem *md); void *on_header_user_data; /* current parse state - or a function that implements it */ grpc_chttp2_hpack_parser_state state; /* future states dependent on the opening op code */ const grpc_chttp2_hpack_parser_state *next_state; /* what to do after skipping prioritization data */ grpc_chttp2_hpack_parser_state after_prioritization; /* the value we're currently parsing */ union { gpr_uint32 *value; grpc_chttp2_hpack_parser_string *str; } parsing; /* string parameters for each chunk */ grpc_chttp2_hpack_parser_string key; grpc_chttp2_hpack_parser_string value; /* parsed index */ gpr_uint32 index; /* length of source bytes for the currently parsing string */ gpr_uint32 strlen; /* number of source bytes read for the currently parsing string */ gpr_uint32 strgot; /* huffman decoding state */ gpr_uint16 huff_state; /* is the string being decoded binary? */ gpr_uint8 binary; /* is the current string huffman encoded? */ gpr_uint8 huff; /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal it should append a metadata boundary at the end of frame */ gpr_uint8 is_boundary; gpr_uint8 is_eof; gpr_uint32 base64_buffer; /* hpack table */ grpc_chttp2_hptbl table; }; void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p, grpc_mdctx *mdctx); void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p); void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); /* returns 1 on success, 0 on error */ int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, const gpr_uint8 *beg, const gpr_uint8 *end); /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for the transport */ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( void *hpack_parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H */ grpc-0.11.1/src/core/transport/chttp2/frame_window_update.c0000644000175000017500000001010412600663151024061 0ustar apollockapollock/* * * 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/transport/chttp2/frame_window_update.h" #include "src/core/transport/chttp2/internal.h" #include gpr_slice grpc_chttp2_window_update_create(gpr_uint32 id, gpr_uint32 window_update) { gpr_slice slice = gpr_slice_malloc(13); gpr_uint8 *p = GPR_SLICE_START_PTR(slice); GPR_ASSERT(window_update); *p++ = 0; *p++ = 0; *p++ = 4; *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE; *p++ = 0; *p++ = id >> 24; *p++ = id >> 16; *p++ = id >> 8; *p++ = id; *p++ = window_update >> 24; *p++ = window_update >> 16; *p++ = window_update >> 8; *p++ = window_update; return slice; } grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( grpc_chttp2_window_update_parser *parser, gpr_uint32 length, gpr_uint8 flags) { if (flags || length != 4) { gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length, flags); return GRPC_CHTTP2_CONNECTION_ERROR; } parser->byte = 0; parser->amount = 0; return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *const end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; grpc_chttp2_window_update_parser *p = parser; while (p->byte != 4 && cur != end) { p->amount |= ((gpr_uint32)*cur) << (8 * (3 - p->byte)); cur++; p->byte++; } if (p->byte == 4) { if (p->amount == 0 || (p->amount & 0x80000000u)) { gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount); return GRPC_CHTTP2_CONNECTION_ERROR; } GPR_ASSERT(is_last); if (transport_parsing->incoming_stream_id != 0) { if (stream_parsing != NULL) { GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("update", transport_parsing, stream_parsing, outgoing_window_update, p->amount); stream_parsing->outgoing_window_update += p->amount; grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } } else { GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("update", transport_parsing, outgoing_window_update, p->amount); transport_parsing->outgoing_window_update += p->amount; } } return GRPC_CHTTP2_PARSE_OK; } grpc-0.11.1/src/core/transport/chttp2/stream_map.c0000644000175000017500000001444312600663151022200 0ustar apollockapollock/* * * 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/transport/chttp2/stream_map.h" #include #include #include #include void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map, size_t initial_capacity) { GPR_ASSERT(initial_capacity > 1); map->keys = gpr_malloc(sizeof(gpr_uint32) * initial_capacity); map->values = gpr_malloc(sizeof(void *) * initial_capacity); map->count = 0; map->free = 0; map->capacity = initial_capacity; } void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map) { gpr_free(map->keys); gpr_free(map->values); } static size_t compact(gpr_uint32 *keys, void **values, size_t count) { size_t i, out; for (i = 0, out = 0; i < count; i++) { if (values[i]) { keys[out] = keys[i]; values[out] = values[i]; out++; } } return out; } void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, gpr_uint32 key, void *value) { size_t count = map->count; size_t capacity = map->capacity; gpr_uint32 *keys = map->keys; void **values = map->values; GPR_ASSERT(count == 0 || keys[count - 1] < key); GPR_ASSERT(value); if (count == capacity) { if (map->free > capacity / 4) { count = compact(keys, values, count); map->free = 0; } else { /* resize when less than 25% of the table is free, because compaction won't help much */ map->capacity = capacity = 3 * capacity / 2; map->keys = keys = gpr_realloc(keys, capacity * sizeof(gpr_uint32)); map->values = values = gpr_realloc(values, capacity * sizeof(void *)); } } keys[count] = key; values[count] = value; map->count = count + 1; } void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, grpc_chttp2_stream_map *dst) { /* if src is empty we dont need to do anything */ if (src->count == src->free) { return; } /* if dst is empty we simply need to swap */ if (dst->count == dst->free) { GPR_SWAP(grpc_chttp2_stream_map, *src, *dst); return; } /* the first element of src must be greater than the last of dst... * however the maps may need compacting for this property to hold */ if (src->keys[0] <= dst->keys[dst->count - 1]) { src->count = compact(src->keys, src->values, src->count); src->free = 0; dst->count = compact(dst->keys, dst->values, dst->count); dst->free = 0; } GPR_ASSERT(src->keys[0] > dst->keys[dst->count - 1]); /* if dst doesn't have capacity, resize */ if (dst->count + src->count > dst->capacity) { dst->capacity = GPR_MAX(dst->capacity * 3 / 2, dst->count + src->count); dst->keys = gpr_realloc(dst->keys, dst->capacity * sizeof(gpr_uint32)); dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *)); } memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(gpr_uint32)); memcpy(dst->values + dst->count, src->values, src->count * sizeof(void *)); dst->count += src->count; dst->free += src->free; src->count = 0; src->free = 0; } static void **find(grpc_chttp2_stream_map *map, gpr_uint32 key) { size_t min_idx = 0; size_t max_idx = map->count; size_t mid_idx; gpr_uint32 *keys = map->keys; void **values = map->values; gpr_uint32 mid_key; if (max_idx == 0) return NULL; while (min_idx < max_idx) { /* find the midpoint, avoiding overflow */ mid_idx = min_idx + ((max_idx - min_idx) / 2); mid_key = keys[mid_idx]; if (mid_key < key) { min_idx = mid_idx + 1; } else if (mid_key > key) { max_idx = mid_idx; } else /* mid_key == key */ { return &values[mid_idx]; } } return NULL; } void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, gpr_uint32 key) { void **pvalue = find(map, key); void *out = NULL; if (pvalue != NULL) { out = *pvalue; *pvalue = NULL; map->free += (out != NULL); /* recognize complete emptyness and ensure we can skip * defragmentation later */ if (map->free == map->count) { map->free = map->count = 0; } } return out; } void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, gpr_uint32 key) { void **pvalue = find(map, key); return pvalue != NULL ? *pvalue : NULL; } size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) { return map->count - map->free; } void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map, void (*f)(void *user_data, gpr_uint32 key, void *value), void *user_data) { size_t i; for (i = 0; i < map->count; i++) { if (map->values[i]) { f(user_data, map->keys[i], map->values[i]); } } } grpc-0.11.1/src/core/transport/chttp2/huffsyms.c0000644000175000017500000001457012600663151021715 0ustar apollockapollock/* * * 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/transport/chttp2/huffsyms.h" /* Constants pulled from the HPACK spec, and converted to C using the vim command: :%s/.* \([0-9a-f]\+\) \[ *\([0-9]\+\)\]/{0x\1, \2},/g */ const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS] = { {0x1ff8, 13}, {0x7fffd8, 23}, {0xfffffe2, 28}, {0xfffffe3, 28}, {0xfffffe4, 28}, {0xfffffe5, 28}, {0xfffffe6, 28}, {0xfffffe7, 28}, {0xfffffe8, 28}, {0xffffea, 24}, {0x3ffffffc, 30}, {0xfffffe9, 28}, {0xfffffea, 28}, {0x3ffffffd, 30}, {0xfffffeb, 28}, {0xfffffec, 28}, {0xfffffed, 28}, {0xfffffee, 28}, {0xfffffef, 28}, {0xffffff0, 28}, {0xffffff1, 28}, {0xffffff2, 28}, {0x3ffffffe, 30}, {0xffffff3, 28}, {0xffffff4, 28}, {0xffffff5, 28}, {0xffffff6, 28}, {0xffffff7, 28}, {0xffffff8, 28}, {0xffffff9, 28}, {0xffffffa, 28}, {0xffffffb, 28}, {0x14, 6}, {0x3f8, 10}, {0x3f9, 10}, {0xffa, 12}, {0x1ff9, 13}, {0x15, 6}, {0xf8, 8}, {0x7fa, 11}, {0x3fa, 10}, {0x3fb, 10}, {0xf9, 8}, {0x7fb, 11}, {0xfa, 8}, {0x16, 6}, {0x17, 6}, {0x18, 6}, {0x0, 5}, {0x1, 5}, {0x2, 5}, {0x19, 6}, {0x1a, 6}, {0x1b, 6}, {0x1c, 6}, {0x1d, 6}, {0x1e, 6}, {0x1f, 6}, {0x5c, 7}, {0xfb, 8}, {0x7ffc, 15}, {0x20, 6}, {0xffb, 12}, {0x3fc, 10}, {0x1ffa, 13}, {0x21, 6}, {0x5d, 7}, {0x5e, 7}, {0x5f, 7}, {0x60, 7}, {0x61, 7}, {0x62, 7}, {0x63, 7}, {0x64, 7}, {0x65, 7}, {0x66, 7}, {0x67, 7}, {0x68, 7}, {0x69, 7}, {0x6a, 7}, {0x6b, 7}, {0x6c, 7}, {0x6d, 7}, {0x6e, 7}, {0x6f, 7}, {0x70, 7}, {0x71, 7}, {0x72, 7}, {0xfc, 8}, {0x73, 7}, {0xfd, 8}, {0x1ffb, 13}, {0x7fff0, 19}, {0x1ffc, 13}, {0x3ffc, 14}, {0x22, 6}, {0x7ffd, 15}, {0x3, 5}, {0x23, 6}, {0x4, 5}, {0x24, 6}, {0x5, 5}, {0x25, 6}, {0x26, 6}, {0x27, 6}, {0x6, 5}, {0x74, 7}, {0x75, 7}, {0x28, 6}, {0x29, 6}, {0x2a, 6}, {0x7, 5}, {0x2b, 6}, {0x76, 7}, {0x2c, 6}, {0x8, 5}, {0x9, 5}, {0x2d, 6}, {0x77, 7}, {0x78, 7}, {0x79, 7}, {0x7a, 7}, {0x7b, 7}, {0x7ffe, 15}, {0x7fc, 11}, {0x3ffd, 14}, {0x1ffd, 13}, {0xffffffc, 28}, {0xfffe6, 20}, {0x3fffd2, 22}, {0xfffe7, 20}, {0xfffe8, 20}, {0x3fffd3, 22}, {0x3fffd4, 22}, {0x3fffd5, 22}, {0x7fffd9, 23}, {0x3fffd6, 22}, {0x7fffda, 23}, {0x7fffdb, 23}, {0x7fffdc, 23}, {0x7fffdd, 23}, {0x7fffde, 23}, {0xffffeb, 24}, {0x7fffdf, 23}, {0xffffec, 24}, {0xffffed, 24}, {0x3fffd7, 22}, {0x7fffe0, 23}, {0xffffee, 24}, {0x7fffe1, 23}, {0x7fffe2, 23}, {0x7fffe3, 23}, {0x7fffe4, 23}, {0x1fffdc, 21}, {0x3fffd8, 22}, {0x7fffe5, 23}, {0x3fffd9, 22}, {0x7fffe6, 23}, {0x7fffe7, 23}, {0xffffef, 24}, {0x3fffda, 22}, {0x1fffdd, 21}, {0xfffe9, 20}, {0x3fffdb, 22}, {0x3fffdc, 22}, {0x7fffe8, 23}, {0x7fffe9, 23}, {0x1fffde, 21}, {0x7fffea, 23}, {0x3fffdd, 22}, {0x3fffde, 22}, {0xfffff0, 24}, {0x1fffdf, 21}, {0x3fffdf, 22}, {0x7fffeb, 23}, {0x7fffec, 23}, {0x1fffe0, 21}, {0x1fffe1, 21}, {0x3fffe0, 22}, {0x1fffe2, 21}, {0x7fffed, 23}, {0x3fffe1, 22}, {0x7fffee, 23}, {0x7fffef, 23}, {0xfffea, 20}, {0x3fffe2, 22}, {0x3fffe3, 22}, {0x3fffe4, 22}, {0x7ffff0, 23}, {0x3fffe5, 22}, {0x3fffe6, 22}, {0x7ffff1, 23}, {0x3ffffe0, 26}, {0x3ffffe1, 26}, {0xfffeb, 20}, {0x7fff1, 19}, {0x3fffe7, 22}, {0x7ffff2, 23}, {0x3fffe8, 22}, {0x1ffffec, 25}, {0x3ffffe2, 26}, {0x3ffffe3, 26}, {0x3ffffe4, 26}, {0x7ffffde, 27}, {0x7ffffdf, 27}, {0x3ffffe5, 26}, {0xfffff1, 24}, {0x1ffffed, 25}, {0x7fff2, 19}, {0x1fffe3, 21}, {0x3ffffe6, 26}, {0x7ffffe0, 27}, {0x7ffffe1, 27}, {0x3ffffe7, 26}, {0x7ffffe2, 27}, {0xfffff2, 24}, {0x1fffe4, 21}, {0x1fffe5, 21}, {0x3ffffe8, 26}, {0x3ffffe9, 26}, {0xffffffd, 28}, {0x7ffffe3, 27}, {0x7ffffe4, 27}, {0x7ffffe5, 27}, {0xfffec, 20}, {0xfffff3, 24}, {0xfffed, 20}, {0x1fffe6, 21}, {0x3fffe9, 22}, {0x1fffe7, 21}, {0x1fffe8, 21}, {0x7ffff3, 23}, {0x3fffea, 22}, {0x3fffeb, 22}, {0x1ffffee, 25}, {0x1ffffef, 25}, {0xfffff4, 24}, {0xfffff5, 24}, {0x3ffffea, 26}, {0x7ffff4, 23}, {0x3ffffeb, 26}, {0x7ffffe6, 27}, {0x3ffffec, 26}, {0x3ffffed, 26}, {0x7ffffe7, 27}, {0x7ffffe8, 27}, {0x7ffffe9, 27}, {0x7ffffea, 27}, {0x7ffffeb, 27}, {0xffffffe, 28}, {0x7ffffec, 27}, {0x7ffffed, 27}, {0x7ffffee, 27}, {0x7ffffef, 27}, {0x7fffff0, 27}, {0x3ffffee, 26}, {0x3fffffff, 30}, }; grpc-0.11.1/src/core/transport/chttp2/timeout_encoding.h0000644000175000017500000000414712600663151023411 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H #include "src/core/support/string.h" #include #define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1) /* Encode/decode timeouts to the GRPC over HTTP2 format; encoding may round up arbitrarily */ void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer); int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H */ grpc-0.11.1/src/core/transport/chttp2/frame_goaway.c0000644000175000017500000001447012600663151022511 0ustar apollockapollock/* * * 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/transport/chttp2/frame_goaway.h" #include "src/core/transport/chttp2/internal.h" #include #include #include void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) { p->debug_data = NULL; } void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) { gpr_free(p->debug_data); } grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( grpc_chttp2_goaway_parser *p, gpr_uint32 length, gpr_uint8 flags) { if (length < 8) { gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length); return GRPC_CHTTP2_CONNECTION_ERROR; } gpr_free(p->debug_data); p->debug_length = length - 8; p->debug_data = gpr_malloc(p->debug_length); p->debug_pos = 0; p->state = GRPC_CHTTP2_GOAWAY_LSI0; return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *const end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; grpc_chttp2_goaway_parser *p = parser; switch (p->state) { case GRPC_CHTTP2_GOAWAY_LSI0: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_LSI0; return GRPC_CHTTP2_PARSE_OK; } p->last_stream_id = ((gpr_uint32)*cur) << 24; ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_LSI1: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_LSI1; return GRPC_CHTTP2_PARSE_OK; } p->last_stream_id |= ((gpr_uint32)*cur) << 16; ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_LSI2: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_LSI2; return GRPC_CHTTP2_PARSE_OK; } p->last_stream_id |= ((gpr_uint32)*cur) << 8; ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_LSI3: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_LSI3; return GRPC_CHTTP2_PARSE_OK; } p->last_stream_id |= ((gpr_uint32)*cur); ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_ERR0: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_ERR0; return GRPC_CHTTP2_PARSE_OK; } p->error_code = ((gpr_uint32)*cur) << 24; ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_ERR1: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_ERR1; return GRPC_CHTTP2_PARSE_OK; } p->error_code |= ((gpr_uint32)*cur) << 16; ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_ERR2: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_ERR2; return GRPC_CHTTP2_PARSE_OK; } p->error_code |= ((gpr_uint32)*cur) << 8; ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_ERR3: if (cur == end) { p->state = GRPC_CHTTP2_GOAWAY_ERR3; return GRPC_CHTTP2_PARSE_OK; } p->error_code |= ((gpr_uint32)*cur); ++cur; /* fallthrough */ case GRPC_CHTTP2_GOAWAY_DEBUG: memcpy(p->debug_data + p->debug_pos, cur, end - cur); p->debug_pos += end - cur; p->state = GRPC_CHTTP2_GOAWAY_DEBUG; if (is_last) { transport_parsing->goaway_received = 1; transport_parsing->goaway_last_stream_index = p->last_stream_id; gpr_slice_unref(transport_parsing->goaway_text); transport_parsing->goaway_error = p->error_code; transport_parsing->goaway_text = gpr_slice_new(p->debug_data, p->debug_length, gpr_free); p->debug_data = NULL; } return GRPC_CHTTP2_PARSE_OK; } gpr_log(GPR_ERROR, "Should never end up here"); abort(); return GRPC_CHTTP2_CONNECTION_ERROR; } void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code, gpr_slice debug_data, gpr_slice_buffer *slice_buffer) { gpr_slice header = gpr_slice_malloc(9 + 4 + 4); gpr_uint8 *p = GPR_SLICE_START_PTR(header); gpr_uint32 frame_length = 4 + 4 + GPR_SLICE_LENGTH(debug_data); /* frame header: length */ *p++ = frame_length >> 16; *p++ = frame_length >> 8; *p++ = frame_length; /* frame header: type */ *p++ = GRPC_CHTTP2_FRAME_GOAWAY; /* frame header: flags */ *p++ = 0; /* frame header: stream id */ *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; /* payload: last stream id */ *p++ = last_stream_id >> 24; *p++ = last_stream_id >> 16; *p++ = last_stream_id >> 8; *p++ = last_stream_id; /* payload: error code */ *p++ = error_code >> 24; *p++ = error_code >> 16; *p++ = error_code >> 8; *p++ = error_code; GPR_ASSERT(p == GPR_SLICE_END_PTR(header)); gpr_slice_buffer_add(slice_buffer, header); gpr_slice_buffer_add(slice_buffer, debug_data); } grpc-0.11.1/src/core/transport/chttp2/stream_encoder.c0000644000175000017500000006101612600663151023040 0ustar apollockapollock/* * * 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/transport/chttp2/stream_encoder.h" #include #include #include #include #include "src/core/transport/chttp2/bin_encoder.h" #include "src/core/transport/chttp2/hpack_table.h" #include "src/core/transport/chttp2/timeout_encoding.h" #include "src/core/transport/chttp2/varint.h" #define HASH_FRAGMENT_1(x) ((x)&255) #define HASH_FRAGMENT_2(x) ((x >> 8) & 255) #define HASH_FRAGMENT_3(x) ((x >> 16) & 255) #define HASH_FRAGMENT_4(x) ((x >> 24) & 255) /* if the probability of this item being seen again is < 1/x then don't add it to the table */ #define ONE_ON_ADD_PROBABILITY 128 /* don't consider adding anything bigger than this to the hpack table */ #define MAX_DECODER_SPACE_USAGE 512 /* what kind of frame our we encoding? */ typedef enum { HEADER, DATA, NONE } frame_type; typedef struct { frame_type cur_frame_type; /* number of bytes in 'output' when we started the frame - used to calculate frame length */ size_t output_length_at_start_of_frame; /* index (in output) of the header for the current frame */ size_t header_idx; /* was the last frame emitted a header? (if yes, we'll need a CONTINUATION */ gpr_uint8 last_was_header; /* have we seen a regular (non-colon-prefixed) header yet? */ gpr_uint8 seen_regular_header; /* output stream id */ gpr_uint32 stream_id; gpr_slice_buffer *output; } framer_state; /* fills p (which is expected to be 9 bytes long) with a data frame header */ static void fill_header(gpr_uint8 *p, gpr_uint8 type, gpr_uint32 id, gpr_uint32 len, gpr_uint8 flags) { *p++ = len >> 16; *p++ = len >> 8; *p++ = len; *p++ = type; *p++ = flags; *p++ = id >> 24; *p++ = id >> 16; *p++ = id >> 8; *p++ = id; } /* finish a frame - fill in the previously reserved header */ static void finish_frame(framer_state *st, int is_header_boundary, int is_last_in_stream) { gpr_uint8 type = 0xff; switch (st->cur_frame_type) { case HEADER: type = st->last_was_header ? GRPC_CHTTP2_FRAME_CONTINUATION : GRPC_CHTTP2_FRAME_HEADER; st->last_was_header = 1; break; case DATA: type = GRPC_CHTTP2_FRAME_DATA; st->last_was_header = 0; is_header_boundary = 0; break; case NONE: return; } fill_header(GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type, st->stream_id, st->output->length - st->output_length_at_start_of_frame, (is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) | (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)); st->cur_frame_type = NONE; } /* begin a new frame: reserve off header space, remember how many bytes we'd output before beginning */ static void begin_frame(framer_state *st, frame_type type) { GPR_ASSERT(type != NONE); GPR_ASSERT(st->cur_frame_type == NONE); st->cur_frame_type = type; st->header_idx = gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9)); st->output_length_at_start_of_frame = st->output->length; } static void begin_new_frame(framer_state *st, frame_type type) { finish_frame(st, 1, 0); st->last_was_header = 0; begin_frame(st, type); } /* make sure that the current frame is of the type desired, and has sufficient space to add at least about_to_add bytes -- finishes the current frame if needed */ static void ensure_frame_type(framer_state *st, frame_type type, int need_bytes) { if (st->cur_frame_type == type && st->output->length - st->output_length_at_start_of_frame + need_bytes <= GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) { return; } finish_frame(st, type != HEADER, 0); begin_frame(st, type); } /* increment a filter count, halve all counts if one element reaches max */ static void inc_filter(gpr_uint8 idx, gpr_uint32 *sum, gpr_uint8 *elems) { elems[idx]++; if (elems[idx] < 255) { (*sum)++; } else { int i; *sum = 0; for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) { elems[i] /= 2; (*sum) += elems[i]; } } } static void add_header_data(framer_state *st, gpr_slice slice) { size_t len = GPR_SLICE_LENGTH(slice); size_t remaining; if (len == 0) return; ensure_frame_type(st, HEADER, 1); remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH + st->output_length_at_start_of_frame - st->output->length; if (len <= remaining) { gpr_slice_buffer_add(st->output, slice); } else { gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining)); add_header_data(st, slice); } } static gpr_uint8 *add_tiny_header_data(framer_state *st, int len) { ensure_frame_type(st, HEADER, len); return gpr_slice_buffer_tiny_add(st->output, len); } /* add an element to the decoder table: returns metadata element to unref */ static grpc_mdelem *add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { gpr_uint32 key_hash = elem->key->hash; gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); gpr_uint32 new_index = c->tail_remote_index + c->table_elems + 1; gpr_uint32 elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) + GPR_SLICE_LENGTH(elem->value->slice); grpc_mdelem *elem_to_unref; /* Reserve space for this element in the remote table: if this overflows the current table, drop elements until it fits, matching the decompressor algorithm */ /* TODO(ctiller): constant */ while (c->table_size + elem_size > 4096) { c->tail_remote_index++; GPR_ASSERT(c->tail_remote_index > 0); GPR_ASSERT(c->table_size >= c->table_elem_size[c->tail_remote_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]); GPR_ASSERT(c->table_elems > 0); c->table_size -= c->table_elem_size[c->tail_remote_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]; c->table_elems--; } GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS); c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] = elem_size; c->table_size += elem_size; c->table_elems++; /* Store this element into {entries,indices}_elem */ if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) { /* already there: update with new index */ c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; elem_to_unref = elem; } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) { /* already there (cuckoo): update with new index */ c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; elem_to_unref = elem; } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) { /* not there, but a free element: add */ c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem; c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; elem_to_unref = NULL; } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) { /* not there (cuckoo), but a free element: add */ c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem; c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; elem_to_unref = NULL; } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { /* not there: replace oldest */ elem_to_unref = c->entries_elems[HASH_FRAGMENT_2(elem_hash)]; c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem; c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; } else { /* not there: replace oldest */ elem_to_unref = c->entries_elems[HASH_FRAGMENT_3(elem_hash)]; c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem; c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; } /* do exactly the same for the key (so we can find by that again too) */ if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) { c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) { c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) { c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) { c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] < c->indices_keys[HASH_FRAGMENT_3(key_hash)]) { GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]); c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; } else { GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]); c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } return elem_to_unref; } static void emit_indexed(grpc_chttp2_hpack_compressor *c, gpr_uint32 index, framer_state *st) { int len = GRPC_CHTTP2_VARINT_LENGTH(index, 1); GRPC_CHTTP2_WRITE_VARINT(index, 1, 0x80, add_tiny_header_data(st, len), len); } static gpr_slice get_wire_value(grpc_mdelem *elem, gpr_uint8 *huffman_prefix) { if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice), GPR_SLICE_LENGTH(elem->key->slice))) { *huffman_prefix = 0x80; return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value); } /* TODO(ctiller): opportunistically compress non-binary headers */ *huffman_prefix = 0x00; return elem->value->slice; } static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 key_index, grpc_mdelem *elem, framer_state *st) { int len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2); gpr_uint8 huffman_prefix; gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); int len_val = GPR_SLICE_LENGTH(value_slice); int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40, add_tiny_header_data(st, len_pfx), len_pfx); GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00, add_tiny_header_data(st, len_val_len), len_val_len); add_header_data(st, gpr_slice_ref(value_slice)); } static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 key_index, grpc_mdelem *elem, framer_state *st) { int len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4); gpr_uint8 huffman_prefix; gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); int len_val = GPR_SLICE_LENGTH(value_slice); int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00, add_tiny_header_data(st, len_pfx), len_pfx); GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00, add_tiny_header_data(st, len_val_len), len_val_len); add_header_data(st, gpr_slice_ref(value_slice)); } static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, framer_state *st) { int len_key = GPR_SLICE_LENGTH(elem->key->slice); gpr_uint8 huffman_prefix; gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); int len_val = GPR_SLICE_LENGTH(value_slice); int len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); *add_tiny_header_data(st, 1) = 0x40; GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, add_tiny_header_data(st, len_key_len), len_key_len); add_header_data(st, gpr_slice_ref(elem->key->slice)); GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); add_header_data(st, gpr_slice_ref(value_slice)); } static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, framer_state *st) { int len_key = GPR_SLICE_LENGTH(elem->key->slice); gpr_uint8 huffman_prefix; gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); int len_val = GPR_SLICE_LENGTH(value_slice); int len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); *add_tiny_header_data(st, 1) = 0x00; GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, add_tiny_header_data(st, len_key_len), len_key_len); add_header_data(st, gpr_slice_ref(elem->key->slice)); GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); add_header_data(st, gpr_slice_ref(value_slice)); } static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 index) { return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index + c->table_elems - index; } /* encode an mdelem; returns metadata element to unref */ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, framer_state *st) { gpr_uint32 key_hash = elem->key->hash; gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); size_t decoder_space_usage; gpr_uint32 indices_key; int should_add_elem; GPR_ASSERT (GPR_SLICE_LENGTH(elem->key->slice) > 0); if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */ st->seen_regular_header = 1; } else if (st->seen_regular_header != 0) { /* reserved header */ gpr_log(GPR_ERROR, "Reserved header (colon-prefixed) happening after regular ones."); abort(); } inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); /* is this elem currently in the decoders table? */ if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem && c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { /* HIT: complete element (first cuckoo hash) */ emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st); return elem; } if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem && c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { /* HIT: complete element (second cuckoo hash) */ emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st); return elem; } /* should this elem be in the table? */ decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) + GPR_SLICE_LENGTH(elem->value->slice); should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE && c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; /* no hits for the elem... maybe there's a key? */ indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ if (should_add_elem) { emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); return add_elem(c, elem); } else { emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); return elem; } abort(); } indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ if (should_add_elem) { emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); return add_elem(c, elem); } else { emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); return elem; } abort(); } /* no elem, key in the table... fall back to literal emission */ if (should_add_elem) { emit_lithdr_incidx_v(c, elem, st); return add_elem(c, elem); } else { emit_lithdr_noidx_v(c, elem, st); return elem; } abort(); } #define STRLEN_LIT(x) (sizeof(x) - 1) #define TIMEOUT_KEY "grpc-timeout" static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, framer_state *st) { char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE]; grpc_mdelem *mdelem; grpc_chttp2_encode_timeout( gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str); mdelem = grpc_mdelem_from_metadata_strings( c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str), grpc_mdstr_from_string(c->mdctx, timeout_str, 0)); mdelem = hpack_enc(c, mdelem, st); if (mdelem) GRPC_MDELEM_UNREF(mdelem); } gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) { gpr_slice slice = gpr_slice_malloc(9); fill_header(GPR_SLICE_START_PTR(slice), GRPC_CHTTP2_FRAME_DATA, id, 0, 1); return slice; } void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c, grpc_mdctx *ctx) { memset(c, 0, sizeof(*c)); c->mdctx = ctx; c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout", 0); } void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { int i; for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) { if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]); if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]); } GRPC_MDSTR_UNREF(c->timeout_key_str); } gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count, gpr_uint32 max_flow_controlled_bytes, grpc_stream_op_buffer *outops) { gpr_slice slice; grpc_stream_op *op; gpr_uint32 max_take_size; gpr_uint32 flow_controlled_bytes_taken = 0; gpr_uint32 curop = 0; gpr_uint8 *p; int compressed_flag_set = 0; while (curop < *inops_count) { GPR_ASSERT(flow_controlled_bytes_taken <= max_flow_controlled_bytes); op = &inops[curop]; switch (op->type) { case GRPC_NO_OP: /* skip */ curop++; break; case GRPC_OP_METADATA: grpc_metadata_batch_assert_ok(&op->data.metadata); /* these just get copied as they don't impact the number of flow controlled bytes */ grpc_sopb_append(outops, op, 1); curop++; break; case GRPC_OP_BEGIN_MESSAGE: /* begin op: for now we just convert the op to a slice and fall through - this lets us reuse the slice framing code below */ compressed_flag_set = (op->data.begin_message.flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0; slice = gpr_slice_malloc(5); p = GPR_SLICE_START_PTR(slice); p[0] = compressed_flag_set; p[1] = op->data.begin_message.length >> 24; p[2] = op->data.begin_message.length >> 16; p[3] = op->data.begin_message.length >> 8; p[4] = op->data.begin_message.length; op->type = GRPC_OP_SLICE; op->data.slice = slice; /* fallthrough */ case GRPC_OP_SLICE: slice = op->data.slice; if (!GPR_SLICE_LENGTH(slice)) { /* skip zero length slices */ gpr_slice_unref(slice); curop++; break; } max_take_size = max_flow_controlled_bytes - flow_controlled_bytes_taken; if (max_take_size == 0) { goto exit_loop; } if (GPR_SLICE_LENGTH(slice) > max_take_size) { slice = gpr_slice_split_head(&op->data.slice, max_take_size); grpc_sopb_add_slice(outops, slice); } else { /* consume this op immediately */ grpc_sopb_append(outops, op, 1); curop++; } flow_controlled_bytes_taken += GPR_SLICE_LENGTH(slice); break; } } exit_loop: *inops_count -= curop; memmove(inops, inops + curop, *inops_count * sizeof(grpc_stream_op)); for (curop = 0; curop < *inops_count; curop++) { if (inops[curop].type == GRPC_OP_METADATA) { grpc_metadata_batch_assert_ok(&inops[curop].data.metadata); } } return flow_controlled_bytes_taken; } void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof, gpr_uint32 stream_id, grpc_chttp2_hpack_compressor *compressor, gpr_slice_buffer *output) { framer_state st; gpr_slice slice; grpc_stream_op *op; gpr_uint32 max_take_size; gpr_uint32 curop = 0; gpr_uint32 unref_op; grpc_mdctx *mdctx = compressor->mdctx; grpc_linked_mdelem *l; int need_unref = 0; gpr_timespec deadline; GPR_ASSERT(stream_id != 0); st.cur_frame_type = NONE; st.last_was_header = 0; st.seen_regular_header = 0; st.stream_id = stream_id; st.output = output; while (curop < ops_count) { op = &ops[curop]; switch (op->type) { case GRPC_NO_OP: case GRPC_OP_BEGIN_MESSAGE: gpr_log( GPR_ERROR, "These stream ops should be filtered out by grpc_chttp2_preencode"); abort(); case GRPC_OP_METADATA: /* Encode a metadata batch; store the returned values, representing a metadata element that needs to be unreffed back into the metadata slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got updated). After this loop, we'll do a batch unref of elements. */ begin_new_frame(&st, HEADER); need_unref |= op->data.metadata.garbage.head != NULL; grpc_metadata_batch_assert_ok(&op->data.metadata); for (l = op->data.metadata.list.head; l; l = l->next) { l->md = hpack_enc(compressor, l->md, &st); need_unref |= l->md != NULL; } deadline = op->data.metadata.deadline; if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) { deadline_enc(compressor, deadline, &st); } curop++; break; case GRPC_OP_SLICE: slice = op->data.slice; if (st.cur_frame_type == DATA && st.output->length - st.output_length_at_start_of_frame == GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) { finish_frame(&st, 0, 0); } ensure_frame_type(&st, DATA, 1); max_take_size = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH + st.output_length_at_start_of_frame - st.output->length; if (GPR_SLICE_LENGTH(slice) > max_take_size) { slice = gpr_slice_split_head(&op->data.slice, max_take_size); } else { /* consume this op immediately */ curop++; } gpr_slice_buffer_add(output, slice); break; } } if (eof && st.cur_frame_type == NONE) { begin_frame(&st, DATA); } finish_frame(&st, 1, eof); if (need_unref) { grpc_mdctx_lock(mdctx); for (unref_op = 0; unref_op < curop; unref_op++) { op = &ops[unref_op]; if (op->type != GRPC_OP_METADATA) continue; for (l = op->data.metadata.list.head; l; l = l->next) { if (l->md) GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md); } for (l = op->data.metadata.garbage.head; l; l = l->next) { GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md); } } grpc_mdctx_unlock(mdctx); } } grpc-0.11.1/src/core/transport/chttp2/frame_ping.h0000644000175000017500000000446112600663151022163 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H #include #include "src/core/transport/chttp2/frame.h" typedef struct { gpr_uint8 byte; gpr_uint8 is_ack; gpr_uint8 opaque_8bytes[8]; } grpc_chttp2_ping_parser; gpr_slice grpc_chttp2_ping_create(gpr_uint8 ack, gpr_uint8 *opaque_8bytes); grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( grpc_chttp2_ping_parser *parser, gpr_uint32 length, gpr_uint8 flags); grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H */ grpc-0.11.1/src/core/transport/chttp2/frame_settings.c0000644000175000017500000002121612600663151023056 0ustar apollockapollock/* * * 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/transport/chttp2/frame_settings.h" #include "src/core/transport/chttp2/internal.h" #include #include "src/core/debug/trace.h" #include "src/core/transport/chttp2/frame.h" #include "src/core/transport/chttp2_transport.h" #include #include /* HTTP/2 mandated initial connection settings */ const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE}, {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff, GRPC_CHTTP2_CLAMP_INVALID_VALUE}, {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE}, {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE}, {"INITIAL_WINDOW_SIZE", 65535, 0, 0xffffffffu, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE}, {"MAX_FRAME_SIZE", 16384, 16384, 16777215, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE}, {"MAX_HEADER_LIST_SIZE", 0xffffffffu, 0, 0xffffffffu, GRPC_CHTTP2_CLAMP_INVALID_VALUE}, }; static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length, gpr_uint8 flags) { *out++ = length >> 16; *out++ = length >> 8; *out++ = length; *out++ = GRPC_CHTTP2_FRAME_SETTINGS; *out++ = flags; *out++ = 0; *out++ = 0; *out++ = 0; *out++ = 0; return out; } gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new, gpr_uint32 force_mask, size_t count) { size_t i; size_t n = 0; gpr_slice output; gpr_uint8 *p; for (i = 0; i < count; i++) { n += (new[i] != old[i] || (force_mask & (1 << i)) != 0); } output = gpr_slice_malloc(9 + 6 * n); p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0); for (i = 0; i < count; i++) { if (new[i] != old[i] || (force_mask & (1 << i)) != 0) { GPR_ASSERT(i); *p++ = i >> 8; *p++ = i; *p++ = new[i] >> 24; *p++ = new[i] >> 16; *p++ = new[i] >> 8; *p++ = new[i]; old[i] = new[i]; } } GPR_ASSERT(p == GPR_SLICE_END_PTR(output)); return output; } gpr_slice grpc_chttp2_settings_ack_create(void) { gpr_slice output = gpr_slice_malloc(9); fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK); return output; } grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags, gpr_uint32 *settings) { parser->target_settings = settings; memcpy(parser->incoming_settings, settings, GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32)); parser->is_ack = 0; parser->state = GRPC_CHTTP2_SPS_ID0; if (flags == GRPC_CHTTP2_FLAG_ACK) { parser->is_ack = 1; if (length != 0) { gpr_log(GPR_ERROR, "non-empty settings ack frame received"); return GRPC_CHTTP2_CONNECTION_ERROR; } return GRPC_CHTTP2_PARSE_OK; } else if (flags != 0) { gpr_log(GPR_ERROR, "invalid flags on settings frame"); return GRPC_CHTTP2_CONNECTION_ERROR; } else if (length % 6 != 0) { gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes"); return GRPC_CHTTP2_CONNECTION_ERROR; } else { return GRPC_CHTTP2_PARSE_OK; } } grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( void *p, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_settings_parser *parser = p; const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice); const gpr_uint8 *end = GPR_SLICE_END_PTR(slice); if (parser->is_ack) { return GRPC_CHTTP2_PARSE_OK; } for (;;) { switch (parser->state) { case GRPC_CHTTP2_SPS_ID0: if (cur == end) { parser->state = GRPC_CHTTP2_SPS_ID0; if (is_last) { transport_parsing->settings_updated = 1; memcpy(parser->target_settings, parser->incoming_settings, GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32)); gpr_slice_buffer_add(&transport_parsing->qbuf, grpc_chttp2_settings_ack_create()); } return GRPC_CHTTP2_PARSE_OK; } parser->id = ((gpr_uint16)*cur) << 8; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_ID1: if (cur == end) { parser->state = GRPC_CHTTP2_SPS_ID1; return GRPC_CHTTP2_PARSE_OK; } parser->id |= (*cur); cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL0: if (cur == end) { parser->state = GRPC_CHTTP2_SPS_VAL0; return GRPC_CHTTP2_PARSE_OK; } parser->value = ((gpr_uint32)*cur) << 24; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL1: if (cur == end) { parser->state = GRPC_CHTTP2_SPS_VAL1; return GRPC_CHTTP2_PARSE_OK; } parser->value |= ((gpr_uint32)*cur) << 16; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL2: if (cur == end) { parser->state = GRPC_CHTTP2_SPS_VAL2; return GRPC_CHTTP2_PARSE_OK; } parser->value |= ((gpr_uint32)*cur) << 8; cur++; /* fallthrough */ case GRPC_CHTTP2_SPS_VAL3: if (cur == end) { parser->state = GRPC_CHTTP2_SPS_VAL3; return GRPC_CHTTP2_PARSE_OK; } else { parser->state = GRPC_CHTTP2_SPS_ID0; } parser->value |= *cur; cur++; if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) { const grpc_chttp2_setting_parameters *sp = &grpc_chttp2_settings_parameters[parser->id]; if (parser->value < sp->min_value || parser->value > sp->max_value) { switch (sp->invalid_value_behavior) { case GRPC_CHTTP2_CLAMP_INVALID_VALUE: parser->value = GPR_CLAMP(parser->value, sp->min_value, sp->max_value); break; case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE: gpr_log(GPR_ERROR, "invalid value %u passed for %s", parser->value, sp->name); return GRPC_CHTTP2_CONNECTION_ERROR; } } if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && parser->incoming_settings[parser->id] != parser->value) { transport_parsing->initial_window_update = (gpr_int64)parser->value - parser->incoming_settings[parser->id]; gpr_log(GPR_DEBUG, "adding %d for initial_window change", (int)transport_parsing->initial_window_update); } parser->incoming_settings[parser->id] = parser->value; if (grpc_http_trace) { gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", transport_parsing->is_client ? "CLI" : "SVR", parser->id, parser->value); } } else { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", parser->id, parser->value); } break; } } } grpc-0.11.1/src/core/transport/chttp2/status_conversion.h0000644000175000017500000000441412600663151023642 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H #include #include "src/core/transport/chttp2/http2_errors.h" /* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error( grpc_status_code status); grpc_status_code grpc_chttp2_http2_error_to_grpc_status( grpc_chttp2_error_code error); /* Conversion of HTTP status codes (:status) to grpc status codes */ grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status); int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H */ grpc-0.11.1/src/core/transport/chttp2/frame_rst_stream.c0000644000175000017500000000653612600663151023411 0ustar apollockapollock/* * * 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/transport/chttp2/frame_rst_stream.h" #include "src/core/transport/chttp2/internal.h" #include #include "src/core/transport/chttp2/frame.h" gpr_slice grpc_chttp2_rst_stream_create(gpr_uint32 id, gpr_uint32 code) { gpr_slice slice = gpr_slice_malloc(13); gpr_uint8 *p = GPR_SLICE_START_PTR(slice); *p++ = 0; *p++ = 0; *p++ = 4; *p++ = GRPC_CHTTP2_FRAME_RST_STREAM; *p++ = 0; *p++ = id >> 24; *p++ = id >> 16; *p++ = id >> 8; *p++ = id; *p++ = code >> 24; *p++ = code >> 16; *p++ = code >> 8; *p++ = code; return slice; } grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( grpc_chttp2_rst_stream_parser *parser, gpr_uint32 length, gpr_uint8 flags) { if (length != 4) { gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length, flags); return GRPC_CHTTP2_CONNECTION_ERROR; } parser->byte = 0; return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *const end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; grpc_chttp2_rst_stream_parser *p = parser; while (p->byte != 4 && cur != end) { p->reason_bytes[p->byte] = *cur; cur++; p->byte++; } if (p->byte == 4) { GPR_ASSERT(is_last); stream_parsing->received_close = 1; stream_parsing->saw_rst_stream = 1; stream_parsing->rst_stream_reason = (((gpr_uint32)p->reason_bytes[0]) << 24) | (((gpr_uint32)p->reason_bytes[1]) << 16) | (((gpr_uint32)p->reason_bytes[2]) << 8) | (((gpr_uint32)p->reason_bytes[3])); } return GRPC_CHTTP2_PARSE_OK; } grpc-0.11.1/src/core/transport/chttp2/frame_window_update.h0000644000175000017500000000465412600663151024103 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H #include #include "src/core/transport/chttp2/frame.h" typedef struct { gpr_uint8 byte; gpr_uint8 is_connection_update; gpr_uint32 amount; } grpc_chttp2_window_update_parser; gpr_slice grpc_chttp2_window_update_create(gpr_uint32 id, gpr_uint32 window_delta); grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( grpc_chttp2_window_update_parser *parser, gpr_uint32 length, gpr_uint8 flags); grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H */ grpc-0.11.1/src/core/transport/chttp2/hpack_tables.txt0000644000175000017500000001033712600663151023063 0ustar apollockapollockStatic table, from the spec: +-------+-----------------------------+---------------+ | Index | Header Name | Header Value | +-------+-----------------------------+---------------+ | 1 | :authority | | | 2 | :method | GET | | 3 | :method | POST | | 4 | :path | / | | 5 | :path | /index.html | | 6 | :scheme | http | | 7 | :scheme | https | | 8 | :status | 200 | | 9 | :status | 204 | | 10 | :status | 206 | | 11 | :status | 304 | | 12 | :status | 400 | | 13 | :status | 404 | | 14 | :status | 500 | | 15 | accept-charset | | | 16 | accept-encoding | gzip, deflate | | 17 | accept-language | | | 18 | accept-ranges | | | 19 | accept | | | 20 | access-control-allow-origin | | | 21 | age | | | 22 | allow | | | 23 | authorization | | | 24 | cache-control | | | 25 | content-disposition | | | 26 | content-encoding | | | 27 | content-language | | | 28 | content-length | | | 29 | content-location | | | 30 | content-range | | | 31 | content-type | | | 32 | cookie | | | 33 | date | | | 34 | etag | | | 35 | expect | | | 36 | expires | | | 37 | from | | | 38 | host | | | 39 | if-match | | | 40 | if-modified-since | | | 41 | if-none-match | | | 42 | if-range | | | 43 | if-unmodified-since | | | 44 | last-modified | | | 45 | link | | | 46 | location | | | 47 | max-forwards | | | 48 | proxy-authenticate | | | 49 | proxy-authorization | | | 50 | range | | | 51 | referer | | | 52 | refresh | | | 53 | retry-after | | | 54 | server | | | 55 | set-cookie | | | 56 | strict-transport-security | | | 57 | transfer-encoding | | | 58 | user-agent | | | 59 | vary | | | 60 | via | | | 61 | www-authenticate | | +-------+-----------------------------+---------------+ grpc-0.11.1/src/core/transport/chttp2/stream_lists.c0000644000175000017500000003463612600663151022567 0ustar apollockapollock/* * * 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/transport/chttp2/internal.h" #include #define TRANSPORT_FROM_GLOBAL(tg) \ ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ global))) #define STREAM_FROM_GLOBAL(sg) \ ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) #define TRANSPORT_FROM_WRITING(tw) \ ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ writing))) #define STREAM_FROM_WRITING(sw) \ ((grpc_chttp2_stream *)((char *)(sw)-offsetof(grpc_chttp2_stream, writing))) #define TRANSPORT_FROM_PARSING(tp) \ ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ parsing))) #define STREAM_FROM_PARSING(sp) \ ((grpc_chttp2_stream *)((char *)(sp)-offsetof(grpc_chttp2_stream, parsing))) /* core list management */ static int stream_list_empty(grpc_chttp2_transport *t, grpc_chttp2_stream_list_id id) { return t->lists[id].head == NULL; } static int stream_list_pop(grpc_chttp2_transport *t, grpc_chttp2_stream **stream, grpc_chttp2_stream_list_id id) { grpc_chttp2_stream *s = t->lists[id].head; if (s) { grpc_chttp2_stream *new_head = s->links[id].next; GPR_ASSERT(s->included[id]); if (new_head) { t->lists[id].head = new_head; new_head->links[id].prev = NULL; } else { t->lists[id].head = NULL; t->lists[id].tail = NULL; } s->included[id] = 0; } *stream = s; return s != 0; } static void stream_list_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_stream_list_id id) { GPR_ASSERT(s->included[id]); s->included[id] = 0; if (s->links[id].prev) { s->links[id].prev->links[id].next = s->links[id].next; } else { GPR_ASSERT(t->lists[id].head == s); t->lists[id].head = s->links[id].next; } if (s->links[id].next) { s->links[id].next->links[id].prev = s->links[id].prev; } else { t->lists[id].tail = s->links[id].prev; } } static void stream_list_maybe_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_stream_list_id id) { if (s->included[id]) { stream_list_remove(t, s, id); } } static void stream_list_add_head(grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_stream_list_id id) { grpc_chttp2_stream *old_head; GPR_ASSERT(!s->included[id]); old_head = t->lists[id].head; s->links[id].next = old_head; s->links[id].prev = NULL; if (old_head) { old_head->links[id].prev = s; } else { t->lists[id].tail = s; } t->lists[id].head = s; s->included[id] = 1; } static void stream_list_add_tail(grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_stream_list_id id) { grpc_chttp2_stream *old_tail; GPR_ASSERT(!s->included[id]); old_tail = t->lists[id].tail; s->links[id].next = NULL; s->links[id].prev = old_tail; if (old_tail) { old_tail->links[id].next = s; } else { t->lists[id].head = s; } t->lists[id].tail = s; s->included[id] = 1; } static void stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_stream_list_id id) { if (s->included[id]) { return; } stream_list_add_tail(t, s, id); } /* wrappers for specializations */ void grpc_chttp2_list_add_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { GPR_ASSERT(stream_global->id != 0); stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE); } void grpc_chttp2_list_add_first_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { GPR_ASSERT(stream_global->id != 0); stream_list_add_head(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE); } int grpc_chttp2_list_pop_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_writing **stream_writing) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_WRITABLE); if (r != 0) { *stream_global = &stream->global; *stream_writing = &stream->writing; } return r; } void grpc_chttp2_list_remove_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE); } void grpc_chttp2_list_add_writing_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing *stream_writing) { stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), STREAM_FROM_WRITING(stream_writing), GRPC_CHTTP2_LIST_WRITING); } int grpc_chttp2_list_have_writing_streams( grpc_chttp2_transport_writing *transport_writing) { return !stream_list_empty(TRANSPORT_FROM_WRITING(transport_writing), GRPC_CHTTP2_LIST_WRITING); } int grpc_chttp2_list_pop_writing_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing **stream_writing) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, GRPC_CHTTP2_LIST_WRITING); if (r != 0) { *stream_writing = &stream->writing; } return r; } void grpc_chttp2_list_add_written_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing *stream_writing) { stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), STREAM_FROM_WRITING(stream_writing), GRPC_CHTTP2_LIST_WRITTEN); } int grpc_chttp2_list_pop_written_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_writing **stream_writing) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, GRPC_CHTTP2_LIST_WRITTEN); if (r != 0) { *stream_global = &stream->global; *stream_writing = &stream->writing; } return r; } void grpc_chttp2_list_add_parsing_seen_stream( grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing) { stream_list_add(TRANSPORT_FROM_PARSING(transport_parsing), STREAM_FROM_PARSING(stream_parsing), GRPC_CHTTP2_LIST_PARSING_SEEN); } int grpc_chttp2_list_pop_parsing_seen_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_parsing **stream_parsing) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream, GRPC_CHTTP2_LIST_PARSING_SEEN); if (r != 0) { *stream_global = &stream->global; *stream_parsing = &stream->parsing; } return r; } void grpc_chttp2_list_add_waiting_for_concurrency( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } int grpc_chttp2_list_pop_waiting_for_concurrency( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); if (r != 0) { *stream_global = &stream->global; } return r; } void grpc_chttp2_list_add_closed_waiting_for_parsing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); } int grpc_chttp2_list_pop_closed_waiting_for_parsing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); if (r != 0) { *stream_global = &stream->global; } return r; } void grpc_chttp2_list_add_cancelled_waiting_for_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING); } int grpc_chttp2_list_pop_cancelled_waiting_for_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING); if (r != 0) { *stream_global = &stream->global; } return r; } void grpc_chttp2_list_add_incoming_window_updated( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED); } int grpc_chttp2_list_pop_incoming_window_updated( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_parsing **stream_parsing) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED); if (r != 0) { *stream_global = &stream->global; *stream_parsing = &stream->parsing; } return r; } void grpc_chttp2_list_remove_incoming_window_updated( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED); } void grpc_chttp2_list_add_read_write_state_changed( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global) { stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED); } int grpc_chttp2_list_pop_read_write_state_changed( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global **stream_global) { grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED); if (r != 0) { *stream_global = &stream->global; } return r; } void grpc_chttp2_register_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s) { stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); } int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s) { stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); } int grpc_chttp2_has_streams(grpc_chttp2_transport *t) { return !stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); } void grpc_chttp2_for_all_streams( grpc_chttp2_transport_global *transport_global, void *user_data, void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, grpc_chttp2_stream_global *stream_global)) { grpc_chttp2_stream *s; grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); for (s = t->lists[GRPC_CHTTP2_LIST_ALL_STREAMS].head; s != NULL; s = s->links[GRPC_CHTTP2_LIST_ALL_STREAMS].next) { cb(transport_global, user_data, &s->global); } } grpc-0.11.1/src/core/transport/chttp2/huffsyms.h0000644000175000017500000000366412600663151021724 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H /* HPACK static huffman table */ #define GRPC_CHTTP2_NUM_HUFFSYMS 257 typedef struct { unsigned bits; unsigned length; } grpc_chttp2_huffsym; extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS]; #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H */ grpc-0.11.1/src/core/transport/chttp2/frame_data.h0000644000175000017500000000615012600663151022134 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H /* Parser for GRPC streams embedded in DATA frames */ #include #include #include "src/core/transport/stream_op.h" #include "src/core/transport/chttp2/frame.h" typedef enum { GRPC_CHTTP2_DATA_FH_0, GRPC_CHTTP2_DATA_FH_1, GRPC_CHTTP2_DATA_FH_2, GRPC_CHTTP2_DATA_FH_3, GRPC_CHTTP2_DATA_FH_4, GRPC_CHTTP2_DATA_FRAME } grpc_chttp2_stream_state; typedef struct { grpc_chttp2_stream_state state; gpr_uint8 is_last_frame; gpr_uint8 frame_type; gpr_uint32 frame_size; int is_frame_compressed; grpc_stream_op_buffer incoming_sopb; } grpc_chttp2_data_parser; /* initialize per-stream state for data frame parsing */ grpc_chttp2_parse_error grpc_chttp2_data_parser_init( grpc_chttp2_data_parser *parser); void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser *parser); /* start processing a new data frame */ grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( grpc_chttp2_data_parser *parser, gpr_uint8 flags); /* handle a slice of a data frame - is_last indicates the last slice of a frame */ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); /* create a slice with an empty data frame and is_last set */ gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H */ grpc-0.11.1/src/core/transport/chttp2/parsing.c0000644000175000017500000010200112600663151021477 0ustar apollockapollock/* * * 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/transport/chttp2/internal.h" #include #include "src/core/transport/chttp2/http2_errors.h" #include "src/core/transport/chttp2/status_conversion.h" #include "src/core/transport/chttp2/timeout_encoding.h" #include #include static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing); static int init_header_frame_parser( grpc_chttp2_transport_parsing *transport_parsing, int is_continuation); static int init_data_frame_parser( grpc_chttp2_transport_parsing *transport_parsing); static int init_rst_stream_parser( grpc_chttp2_transport_parsing *transport_parsing); static int init_settings_frame_parser( grpc_chttp2_transport_parsing *transport_parsing); static int init_window_update_frame_parser( grpc_chttp2_transport_parsing *transport_parsing); static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing); static int init_goaway_parser(grpc_chttp2_transport_parsing *transport_parsing); static int init_skip_frame_parser( grpc_chttp2_transport_parsing *transport_parsing, int is_header); static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing, gpr_slice slice, int is_last); void grpc_chttp2_prepare_to_read( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_parsing *stream_parsing; transport_parsing->next_stream_id = transport_global->next_stream_id; /* update the parsing view of incoming window */ if (transport_parsing->incoming_window != transport_global->incoming_window) { GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "parse", transport_parsing, incoming_window, (gpr_int64)transport_global->incoming_window - (gpr_int64)transport_parsing->incoming_window); transport_parsing->incoming_window = transport_global->incoming_window; } while (grpc_chttp2_list_pop_incoming_window_updated( transport_global, transport_parsing, &stream_global, &stream_parsing)) { stream_parsing->id = stream_global->id; if (stream_parsing->incoming_window != stream_global->incoming_window) { GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "parse", transport_parsing, stream_parsing, incoming_window, (gpr_int64)stream_global->incoming_window - (gpr_int64)stream_parsing->incoming_window); stream_parsing->incoming_window = stream_global->incoming_window; } } } void grpc_chttp2_publish_reads( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_parsing *transport_parsing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_parsing *stream_parsing; /* transport_parsing->last_incoming_stream_id is used as last-grpc_chttp2_stream-id when sending GOAWAY frame. https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8 says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream ID. So, since we don't have server pushed streams, client should send GOAWAY last-grpc_chttp2_stream-id=0 in this case. */ if (!transport_parsing->is_client) { transport_global->last_incoming_stream_id = transport_parsing->incoming_stream_id; } /* copy parsing qbuf to global qbuf */ gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf); /* update global settings */ if (transport_parsing->settings_updated) { memcpy(transport_global->settings[GRPC_PEER_SETTINGS], transport_parsing->settings, sizeof(transport_parsing->settings)); transport_parsing->settings_updated = 0; } /* update settings based on ack if received */ if (transport_parsing->settings_ack_received) { memcpy(transport_global->settings[GRPC_ACKED_SETTINGS], transport_global->settings[GRPC_SENT_SETTINGS], GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32)); transport_parsing->settings_ack_received = 0; } /* move goaway to the global state if we received one (it will be published later */ if (transport_parsing->goaway_received) { grpc_chttp2_add_incoming_goaway(transport_global, transport_parsing->goaway_error, transport_parsing->goaway_text); transport_parsing->goaway_text = gpr_empty_slice(); transport_parsing->goaway_received = 0; } /* propagate flow control tokens to global state */ if (transport_parsing->outgoing_window_update) { GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "parsed", transport_global, outgoing_window, transport_parsing->outgoing_window_update); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "parsed", transport_parsing, outgoing_window_update, -(gpr_int64)transport_parsing->outgoing_window_update); transport_global->outgoing_window += transport_parsing->outgoing_window_update; transport_parsing->outgoing_window_update = 0; } if (transport_parsing->incoming_window_delta) { GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "parsed", transport_global, incoming_window, -(gpr_int64)transport_parsing->incoming_window_delta); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "parsed", transport_parsing, incoming_window_delta, -(gpr_int64)transport_parsing->incoming_window_delta); transport_global->incoming_window -= transport_parsing->incoming_window_delta; transport_parsing->incoming_window_delta = 0; } /* for each stream that saw an update, fixup global state */ while (grpc_chttp2_list_pop_parsing_seen_stream( transport_global, transport_parsing, &stream_global, &stream_parsing)) { /* update incoming flow control window */ if (stream_parsing->incoming_window_delta) { GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "parsed", transport_parsing, stream_global, incoming_window, -(gpr_int64)stream_parsing->incoming_window_delta); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "parsed", transport_parsing, stream_parsing, incoming_window_delta, -(gpr_int64)stream_parsing->incoming_window_delta); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "parsed", transport_parsing, stream_global, max_recv_bytes, -(gpr_int64)stream_parsing->incoming_window_delta); stream_global->incoming_window -= stream_parsing->incoming_window_delta; GPR_ASSERT(stream_global->max_recv_bytes >= stream_parsing->incoming_window_delta); stream_global->max_recv_bytes -= stream_parsing->incoming_window_delta; stream_parsing->incoming_window_delta = 0; grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } /* update outgoing flow control window */ if (stream_parsing->outgoing_window_update) { int was_zero = stream_global->outgoing_window <= 0; int is_zero; GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("parsed", transport_parsing, stream_global, outgoing_window, stream_parsing->outgoing_window_update); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "parsed", transport_parsing, stream_parsing, outgoing_window_update, -(gpr_int64)stream_parsing->outgoing_window_update); stream_global->outgoing_window += stream_parsing->outgoing_window_update; stream_parsing->outgoing_window_update = 0; is_zero = stream_global->outgoing_window <= 0; if (was_zero && !is_zero) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } } /* updating closed status */ if (stream_parsing->received_close) { stream_global->read_closed = 1; grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } if (stream_parsing->saw_rst_stream) { stream_global->cancelled = 1; stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status( stream_parsing->rst_stream_reason); if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) { stream_global->published_cancelled = 1; } grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } /* publish incoming stream ops */ if (stream_parsing->data_parser.incoming_sopb.nops > 0) { grpc_incoming_metadata_buffer_move_to_referencing_sopb( &stream_parsing->incoming_metadata, &stream_global->incoming_metadata, &stream_parsing->data_parser.incoming_sopb); grpc_sopb_move_to(&stream_parsing->data_parser.incoming_sopb, &stream_global->incoming_sopb); grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } } } int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing, gpr_slice slice) { gpr_uint8 *beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; if (cur == end) return 1; switch (transport_parsing->deframe_state) { case GRPC_DTS_CLIENT_PREFIX_0: case GRPC_DTS_CLIENT_PREFIX_1: case GRPC_DTS_CLIENT_PREFIX_2: case GRPC_DTS_CLIENT_PREFIX_3: case GRPC_DTS_CLIENT_PREFIX_4: case GRPC_DTS_CLIENT_PREFIX_5: case GRPC_DTS_CLIENT_PREFIX_6: case GRPC_DTS_CLIENT_PREFIX_7: case GRPC_DTS_CLIENT_PREFIX_8: case GRPC_DTS_CLIENT_PREFIX_9: case GRPC_DTS_CLIENT_PREFIX_10: case GRPC_DTS_CLIENT_PREFIX_11: case GRPC_DTS_CLIENT_PREFIX_12: case GRPC_DTS_CLIENT_PREFIX_13: case GRPC_DTS_CLIENT_PREFIX_14: case GRPC_DTS_CLIENT_PREFIX_15: case GRPC_DTS_CLIENT_PREFIX_16: case GRPC_DTS_CLIENT_PREFIX_17: case GRPC_DTS_CLIENT_PREFIX_18: case GRPC_DTS_CLIENT_PREFIX_19: case GRPC_DTS_CLIENT_PREFIX_20: case GRPC_DTS_CLIENT_PREFIX_21: case GRPC_DTS_CLIENT_PREFIX_22: case GRPC_DTS_CLIENT_PREFIX_23: while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) { if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing ->deframe_state]) { gpr_log(GPR_INFO, "Connect string mismatch: expected '%c' (%d) got '%c' (%d) " "at byte %d", GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing ->deframe_state], (int)(gpr_uint8)GRPC_CHTTP2_CLIENT_CONNECT_STRING [transport_parsing->deframe_state], *cur, (int)*cur, transport_parsing->deframe_state); return 0; } ++cur; ++transport_parsing->deframe_state; } if (cur == end) { return 1; } /* fallthrough */ dts_fh_0: case GRPC_DTS_FH_0: GPR_ASSERT(cur < end); transport_parsing->incoming_frame_size = ((gpr_uint32)*cur) << 16; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_1; return 1; } /* fallthrough */ case GRPC_DTS_FH_1: GPR_ASSERT(cur < end); transport_parsing->incoming_frame_size |= ((gpr_uint32)*cur) << 8; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_2; return 1; } /* fallthrough */ case GRPC_DTS_FH_2: GPR_ASSERT(cur < end); transport_parsing->incoming_frame_size |= *cur; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_3; return 1; } /* fallthrough */ case GRPC_DTS_FH_3: GPR_ASSERT(cur < end); transport_parsing->incoming_frame_type = *cur; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_4; return 1; } /* fallthrough */ case GRPC_DTS_FH_4: GPR_ASSERT(cur < end); transport_parsing->incoming_frame_flags = *cur; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_5; return 1; } /* fallthrough */ case GRPC_DTS_FH_5: GPR_ASSERT(cur < end); transport_parsing->incoming_stream_id = (((gpr_uint32)*cur) & 0x7f) << 24; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_6; return 1; } /* fallthrough */ case GRPC_DTS_FH_6: GPR_ASSERT(cur < end); transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 16; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_7; return 1; } /* fallthrough */ case GRPC_DTS_FH_7: GPR_ASSERT(cur < end); transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 8; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_8; return 1; } /* fallthrough */ case GRPC_DTS_FH_8: GPR_ASSERT(cur < end); transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur); transport_parsing->deframe_state = GRPC_DTS_FRAME; if (!init_frame_parser(transport_parsing)) { return 0; } if (transport_parsing->incoming_stream_id) { transport_parsing->last_incoming_stream_id = transport_parsing->incoming_stream_id; } if (transport_parsing->incoming_frame_size == 0) { if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1)) { return 0; } transport_parsing->incoming_stream = NULL; if (++cur == end) { transport_parsing->deframe_state = GRPC_DTS_FH_0; return 1; } goto dts_fh_0; /* loop */ } if (++cur == end) { return 1; } /* fallthrough */ case GRPC_DTS_FRAME: GPR_ASSERT(cur < end); if ((gpr_uint32)(end - cur) == transport_parsing->incoming_frame_size) { if (!parse_frame_slice( transport_parsing, gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) { return 0; } transport_parsing->deframe_state = GRPC_DTS_FH_0; transport_parsing->incoming_stream = NULL; return 1; } else if ((gpr_uint32)(end - cur) > transport_parsing->incoming_frame_size) { if (!parse_frame_slice( transport_parsing, gpr_slice_sub_no_ref( slice, cur - beg, cur + transport_parsing->incoming_frame_size - beg), 1)) { return 0; } cur += transport_parsing->incoming_frame_size; transport_parsing->incoming_stream = NULL; goto dts_fh_0; /* loop */ } else { if (!parse_frame_slice( transport_parsing, gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) { return 0; } transport_parsing->incoming_frame_size -= (end - cur); return 1; } gpr_log(GPR_ERROR, "should never reach here"); abort(); } gpr_log(GPR_ERROR, "should never reach here"); abort(); return 0; } static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) { if (transport_parsing->expect_continuation_stream_id != 0) { if (transport_parsing->incoming_frame_type != GRPC_CHTTP2_FRAME_CONTINUATION) { gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x", transport_parsing->incoming_frame_type); return 0; } if (transport_parsing->expect_continuation_stream_id != transport_parsing->incoming_stream_id) { gpr_log(GPR_ERROR, "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " "grpc_chttp2_stream %08x", transport_parsing->expect_continuation_stream_id, transport_parsing->incoming_stream_id); return 0; } return init_header_frame_parser(transport_parsing, 1); } switch (transport_parsing->incoming_frame_type) { case GRPC_CHTTP2_FRAME_DATA: return init_data_frame_parser(transport_parsing); case GRPC_CHTTP2_FRAME_HEADER: return init_header_frame_parser(transport_parsing, 0); case GRPC_CHTTP2_FRAME_CONTINUATION: gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame"); return 0; case GRPC_CHTTP2_FRAME_RST_STREAM: return init_rst_stream_parser(transport_parsing); case GRPC_CHTTP2_FRAME_SETTINGS: return init_settings_frame_parser(transport_parsing); case GRPC_CHTTP2_FRAME_WINDOW_UPDATE: return init_window_update_frame_parser(transport_parsing); case GRPC_CHTTP2_FRAME_PING: return init_ping_parser(transport_parsing); case GRPC_CHTTP2_FRAME_GOAWAY: return init_goaway_parser(transport_parsing); default: gpr_log(GPR_ERROR, "Unknown frame type %02x", transport_parsing->incoming_frame_type); return init_skip_frame_parser(transport_parsing, 0); } } static grpc_chttp2_parse_error skip_parser( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { return GRPC_CHTTP2_PARSE_OK; } static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } static int init_skip_frame_parser( grpc_chttp2_transport_parsing *transport_parsing, int is_header) { if (is_header) { int is_eoh = transport_parsing->expect_continuation_stream_id != 0; transport_parsing->parser = grpc_chttp2_header_parser_parse; transport_parsing->parser_data = &transport_parsing->hpack_parser; transport_parsing->hpack_parser.on_header = skip_header; transport_parsing->hpack_parser.on_header_user_data = NULL; transport_parsing->hpack_parser.is_boundary = is_eoh; transport_parsing->hpack_parser.is_eof = is_eoh ? transport_parsing->header_eof : 0; } else { transport_parsing->parser = skip_parser; } return 1; } void grpc_chttp2_parsing_become_skip_parser( grpc_chttp2_transport_parsing *transport_parsing) { init_skip_frame_parser( transport_parsing, transport_parsing->parser == grpc_chttp2_header_parser_parse); } static grpc_chttp2_parse_error update_incoming_window( grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing) { if (transport_parsing->incoming_frame_size > transport_parsing->incoming_window) { gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", transport_parsing->incoming_frame_size, transport_parsing->incoming_window); return GRPC_CHTTP2_CONNECTION_ERROR; } if (transport_parsing->incoming_frame_size > stream_parsing->incoming_window) { gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", transport_parsing->incoming_frame_size, stream_parsing->incoming_window); return GRPC_CHTTP2_CONNECTION_ERROR; } GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "data", transport_parsing, incoming_window, -(gpr_int64)transport_parsing->incoming_frame_size); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("data", transport_parsing, incoming_window_delta, transport_parsing->incoming_frame_size); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "data", transport_parsing, stream_parsing, incoming_window, -(gpr_int64)transport_parsing->incoming_frame_size); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("data", transport_parsing, stream_parsing, incoming_window_delta, transport_parsing->incoming_frame_size); transport_parsing->incoming_window -= transport_parsing->incoming_frame_size; transport_parsing->incoming_window_delta += transport_parsing->incoming_frame_size; stream_parsing->incoming_window -= transport_parsing->incoming_frame_size; stream_parsing->incoming_window_delta += transport_parsing->incoming_frame_size; grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); return GRPC_CHTTP2_PARSE_OK; } static int init_data_frame_parser( grpc_chttp2_transport_parsing *transport_parsing) { grpc_chttp2_stream_parsing *stream_parsing = grpc_chttp2_parsing_lookup_stream(transport_parsing, transport_parsing->incoming_stream_id); grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK; if (!stream_parsing || stream_parsing->received_close) return init_skip_frame_parser(transport_parsing, 0); if (err == GRPC_CHTTP2_PARSE_OK) { err = update_incoming_window(transport_parsing, stream_parsing); } if (err == GRPC_CHTTP2_PARSE_OK) { err = grpc_chttp2_data_parser_begin_frame( &stream_parsing->data_parser, transport_parsing->incoming_frame_flags); } switch (err) { case GRPC_CHTTP2_PARSE_OK: transport_parsing->incoming_stream = stream_parsing; transport_parsing->parser = grpc_chttp2_data_parser_parse; transport_parsing->parser_data = &stream_parsing->data_parser; return 1; case GRPC_CHTTP2_STREAM_ERROR: stream_parsing->received_close = 1; stream_parsing->saw_rst_stream = 1; stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; gpr_slice_buffer_add( &transport_parsing->qbuf, grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, GRPC_CHTTP2_PROTOCOL_ERROR)); return init_skip_frame_parser(transport_parsing, 0); case GRPC_CHTTP2_CONNECTION_ERROR: return 0; } gpr_log(GPR_ERROR, "should never reach here"); abort(); return 0; } static void free_timeout(void *p) { gpr_free(p); } static void on_header(void *tp, grpc_mdelem *md) { grpc_chttp2_transport_parsing *transport_parsing = tp; grpc_chttp2_stream_parsing *stream_parsing = transport_parsing->incoming_stream; GPR_ASSERT(stream_parsing); GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id, transport_parsing->is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); if (md->key == transport_parsing->str_grpc_timeout) { gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); if (!cached_timeout) { /* not already parsed: parse it now, and store the result away */ cached_timeout = gpr_malloc(sizeof(gpr_timespec)); if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value), cached_timeout)) { gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", grpc_mdstr_as_c_string(md->value)); *cached_timeout = gpr_inf_future(GPR_CLOCK_REALTIME); } grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); } grpc_chttp2_incoming_metadata_buffer_set_deadline( &stream_parsing->incoming_metadata, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); GRPC_MDELEM_UNREF(md); } else { grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata, md); } grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } static int init_header_frame_parser( grpc_chttp2_transport_parsing *transport_parsing, int is_continuation) { int is_eoh = (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0; int via_accept = 0; grpc_chttp2_stream_parsing *stream_parsing; if (is_eoh) { transport_parsing->expect_continuation_stream_id = 0; } else { transport_parsing->expect_continuation_stream_id = transport_parsing->incoming_stream_id; } if (!is_continuation) { transport_parsing->header_eof = (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0; } /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */ stream_parsing = grpc_chttp2_parsing_lookup_stream( transport_parsing, transport_parsing->incoming_stream_id); if (stream_parsing == NULL) { if (is_continuation) { gpr_log(GPR_ERROR, "grpc_chttp2_stream disbanded before CONTINUATION received"); return init_skip_frame_parser(transport_parsing, 1); } if (transport_parsing->is_client) { if ((transport_parsing->incoming_stream_id & 1) && transport_parsing->incoming_stream_id < transport_parsing->next_stream_id) { /* this is an old (probably cancelled) grpc_chttp2_stream */ } else { gpr_log(GPR_ERROR, "ignoring new grpc_chttp2_stream creation on client"); } return init_skip_frame_parser(transport_parsing, 1); } else if (transport_parsing->last_incoming_stream_id > transport_parsing->incoming_stream_id) { gpr_log(GPR_ERROR, "ignoring out of order new grpc_chttp2_stream request on server; " "last grpc_chttp2_stream " "id=%d, new grpc_chttp2_stream id=%d", transport_parsing->last_incoming_stream_id, transport_parsing->incoming_stream_id); return init_skip_frame_parser(transport_parsing, 1); } else if ((transport_parsing->incoming_stream_id & 1) == 0) { gpr_log(GPR_ERROR, "ignoring grpc_chttp2_stream with non-client generated index %d", transport_parsing->incoming_stream_id); return init_skip_frame_parser(transport_parsing, 1); } stream_parsing = transport_parsing->incoming_stream = grpc_chttp2_parsing_accept_stream( transport_parsing, transport_parsing->incoming_stream_id); if (stream_parsing == NULL) { gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"); return init_skip_frame_parser(transport_parsing, 1); } via_accept = 1; } else { transport_parsing->incoming_stream = stream_parsing; } GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1)); if (stream_parsing->received_close) { gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header"); transport_parsing->incoming_stream = NULL; return init_skip_frame_parser(transport_parsing, 1); } transport_parsing->parser = grpc_chttp2_header_parser_parse; transport_parsing->parser_data = &transport_parsing->hpack_parser; transport_parsing->hpack_parser.on_header = on_header; transport_parsing->hpack_parser.on_header_user_data = transport_parsing; transport_parsing->hpack_parser.is_boundary = is_eoh; transport_parsing->hpack_parser.is_eof = is_eoh ? transport_parsing->header_eof : 0; if (!is_continuation && (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser); } return 1; } static int init_window_update_frame_parser( grpc_chttp2_transport_parsing *transport_parsing) { int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame( &transport_parsing->simple.window_update, transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_flags); if (transport_parsing->incoming_stream_id) { transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( transport_parsing, transport_parsing->incoming_stream_id); } transport_parsing->parser = grpc_chttp2_window_update_parser_parse; transport_parsing->parser_data = &transport_parsing->simple.window_update; return ok; } static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing) { int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame( &transport_parsing->simple.ping, transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_flags); transport_parsing->parser = grpc_chttp2_ping_parser_parse; transport_parsing->parser_data = &transport_parsing->simple.ping; return ok; } static int init_rst_stream_parser( grpc_chttp2_transport_parsing *transport_parsing) { int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame( &transport_parsing->simple.rst_stream, transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_flags); transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( transport_parsing, transport_parsing->incoming_stream_id); if (!transport_parsing->incoming_stream) { return init_skip_frame_parser(transport_parsing, 0); } transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; transport_parsing->parser_data = &transport_parsing->simple.rst_stream; return ok; } static int init_goaway_parser( grpc_chttp2_transport_parsing *transport_parsing) { int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame( &transport_parsing->goaway_parser, transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_flags); transport_parsing->parser = grpc_chttp2_goaway_parser_parse; transport_parsing->parser_data = &transport_parsing->goaway_parser; return ok; } static int init_settings_frame_parser( grpc_chttp2_transport_parsing *transport_parsing) { int ok; if (transport_parsing->incoming_stream_id != 0) { gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d", transport_parsing->incoming_stream_id); return 0; } ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame( &transport_parsing->simple.settings, transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_flags, transport_parsing->settings); if (!ok) { return 0; } if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { transport_parsing->settings_ack_received = 1; } transport_parsing->parser = grpc_chttp2_settings_parser_parse; transport_parsing->parser_data = &transport_parsing->simple.settings; return ok; } /* static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) { return window + window_update < MAX_WINDOW; } */ static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing = transport_parsing->incoming_stream; switch (transport_parsing->parser(transport_parsing->parser_data, transport_parsing, stream_parsing, slice, is_last)) { case GRPC_CHTTP2_PARSE_OK: if (stream_parsing) { grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); } return 1; case GRPC_CHTTP2_STREAM_ERROR: grpc_chttp2_parsing_become_skip_parser(transport_parsing); if (stream_parsing) { stream_parsing->saw_rst_stream = 1; stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; gpr_slice_buffer_add( &transport_parsing->qbuf, grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, GRPC_CHTTP2_PROTOCOL_ERROR)); } return 1; case GRPC_CHTTP2_CONNECTION_ERROR: return 0; } gpr_log(GPR_ERROR, "should never reach here"); abort(); return 0; } grpc-0.11.1/src/core/transport/chttp2/timeout_encoding.c0000644000175000017500000001265712600663151023411 0ustar apollockapollock/* * * 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/transport/chttp2/timeout_encoding.h" #include #include #include "src/core/support/string.h" static int round_up(int x, int divisor) { return (x / divisor + (x % divisor != 0)) * divisor; } /* round an integer up to the next value with three significant figures */ static int round_up_to_three_sig_figs(int x) { if (x < 1000) return x; if (x < 10000) return round_up(x, 10); if (x < 100000) return round_up(x, 100); if (x < 1000000) return round_up(x, 1000); if (x < 10000000) return round_up(x, 10000); if (x < 100000000) return round_up(x, 100000); if (x < 1000000000) return round_up(x, 1000000); return round_up(x, 10000000); } /* encode our minimum viable timeout value */ static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); } static void enc_ext(char *buffer, long value, char ext) { int n = gpr_ltoa(value, buffer); buffer[n] = ext; buffer[n + 1] = 0; } static void enc_seconds(char *buffer, long sec) { if (sec % 3600 == 0) { enc_ext(buffer, sec / 3600, 'H'); } else if (sec % 60 == 0) { enc_ext(buffer, sec / 60, 'M'); } else { enc_ext(buffer, sec, 'S'); } } static void enc_nanos(char *buffer, int x) { x = round_up_to_three_sig_figs(x); if (x < 100000) { if (x % 1000 == 0) { enc_ext(buffer, x / 1000, 'u'); } else { enc_ext(buffer, x, 'n'); } } else if (x < 100000000) { if (x % 1000000 == 0) { enc_ext(buffer, x / 1000000, 'm'); } else { enc_ext(buffer, x / 1000, 'u'); } } else if (x < 1000000000) { enc_ext(buffer, x / 1000000, 'm'); } else { /* note that this is only ever called with times of less than one second, so if we reach here the time must have been rounded up to a whole second (and no more) */ memcpy(buffer, "1S", 3); } } static void enc_micros(char *buffer, int x) { x = round_up_to_three_sig_figs(x); if (x < 100000) { if (x % 1000 == 0) { enc_ext(buffer, x / 1000, 'm'); } else { enc_ext(buffer, x, 'u'); } } else if (x < 100000000) { if (x % 1000000 == 0) { enc_ext(buffer, x / 1000000, 'S'); } else { enc_ext(buffer, x / 1000, 'm'); } } else { enc_ext(buffer, x / 1000000, 'S'); } } void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) { if (timeout.tv_sec < 0) { enc_tiny(buffer); } else if (timeout.tv_sec == 0) { enc_nanos(buffer, timeout.tv_nsec); } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) { enc_micros(buffer, timeout.tv_sec * 1000000 + (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0))); } else { enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0)); } } static int is_all_whitespace(const char *p) { while (*p == ' ') p++; return *p == 0; } int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) { gpr_uint32 x = 0; const char *p = buffer; int have_digit = 0; /* skip whitespace */ for (; *p == ' '; p++) ; /* decode numeric part */ for (; *p >= '0' && *p <= '9'; p++) { gpr_uint32 xp = x * 10 + *p - '0'; have_digit = 1; if (xp < x) { *timeout = gpr_inf_future(GPR_CLOCK_REALTIME); return 1; } x = xp; } if (!have_digit) return 0; /* skip whitespace */ for (; *p == ' '; p++) ; /* decode unit specifier */ switch (*p) { case 'n': *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN); break; case 'u': *timeout = gpr_time_from_micros(x, GPR_TIMESPAN); break; case 'm': *timeout = gpr_time_from_millis(x, GPR_TIMESPAN); break; case 'S': *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN); break; case 'M': *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN); break; case 'H': *timeout = gpr_time_from_hours(x, GPR_TIMESPAN); break; default: return 0; } p++; return is_all_whitespace(p); } grpc-0.11.1/src/core/transport/chttp2/http2_errors.h0000644000175000017500000000454412600663151022513 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H /* error codes for RST_STREAM from http2 draft 14 section 7 */ typedef enum { GRPC_CHTTP2_NO_ERROR = 0x0, GRPC_CHTTP2_PROTOCOL_ERROR = 0x1, GRPC_CHTTP2_INTERNAL_ERROR = 0x2, GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3, GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4, GRPC_CHTTP2_STREAM_CLOSED = 0x5, GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6, GRPC_CHTTP2_REFUSED_STREAM = 0x7, GRPC_CHTTP2_CANCEL = 0x8, GRPC_CHTTP2_COMPRESSION_ERROR = 0x9, GRPC_CHTTP2_CONNECT_ERROR = 0xa, GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb, GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc, /* force use of a default clause */ GRPC_CHTTP2__ERROR_DO_NOT_USE = -1 } grpc_chttp2_error_code; #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H */ grpc-0.11.1/src/core/transport/chttp2/stream_map.h0000644000175000017500000000706412600663151022206 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H #include #include /* Data structure to map a gpr_uint32 to a data object (represented by a void*) Represented as a sorted array of keys, and a corresponding array of values. Lookups are performed with binary search. Adds are restricted to strictly higher keys than previously seen (this is guaranteed by http2). */ typedef struct { gpr_uint32 *keys; void **values; size_t count; size_t free; size_t capacity; } grpc_chttp2_stream_map; void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map, size_t initial_capacity); void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map); /* Add a new key: given http2 semantics, new keys must always be greater than existing keys - this is asserted */ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, gpr_uint32 key, void *value); /* Delete an existing key - returns the previous value of the key if it existed, or NULL otherwise */ void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, gpr_uint32 key); /* Move all elements of src into dst */ void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, grpc_chttp2_stream_map *dst); /* Return an existing key, or NULL if it does not exist */ void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, gpr_uint32 key); /* How many (populated) entries are in the stream map? */ size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map); /* Callback on each stream */ void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map, void (*f)(void *user_data, gpr_uint32 key, void *value), void *user_data); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H */ grpc-0.11.1/src/core/transport/chttp2/varint.h0000644000175000017500000000667112600663151021364 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_VARINT_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_VARINT_H #include /* Helpers for hpack varint encoding */ /* length of a value that needs varint tail encoding (it's bigger than can be bitpacked into the opcode byte) - returned value includes the length of the opcode byte */ int grpc_chttp2_hpack_varint_length(gpr_uint32 tail_value); void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value, gpr_uint8* target, int tail_length); /* maximum value that can be bitpacked with the opcode if the opcode has a prefix of length prefix_bits */ #define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) ((1 << (8 - (prefix_bits))) - 1) /* length required to bitpack a value */ #define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \ ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \ ? 1 \ : grpc_chttp2_hpack_varint_length( \ (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits))) #define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length) \ do { \ gpr_uint8* tgt = target; \ if ((length) == 1) { \ (tgt)[0] = (prefix_or) | (n); \ } else { \ (tgt)[0] = (prefix_or) | GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits); \ grpc_chttp2_hpack_write_varint_tail( \ (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1, (length)-1); \ } \ } while (0) #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_VARINT_H */ grpc-0.11.1/src/core/transport/chttp2/frame_ping.c0000644000175000017500000000703312600663151022154 0ustar apollockapollock/* * * 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/transport/chttp2/frame_ping.h" #include "src/core/transport/chttp2/internal.h" #include #include #include gpr_slice grpc_chttp2_ping_create(gpr_uint8 ack, gpr_uint8 *opaque_8bytes) { gpr_slice slice = gpr_slice_malloc(9 + 8); gpr_uint8 *p = GPR_SLICE_START_PTR(slice); *p++ = 0; *p++ = 0; *p++ = 8; *p++ = GRPC_CHTTP2_FRAME_PING; *p++ = ack ? 1 : 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; memcpy(p, opaque_8bytes, 8); return slice; } grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( grpc_chttp2_ping_parser *parser, gpr_uint32 length, gpr_uint8 flags) { if (flags & 0xfe || length != 8) { gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags); return GRPC_CHTTP2_CONNECTION_ERROR; } parser->byte = 0; parser->is_ack = flags; return GRPC_CHTTP2_PARSE_OK; } grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice); gpr_uint8 *const end = GPR_SLICE_END_PTR(slice); gpr_uint8 *cur = beg; grpc_chttp2_ping_parser *p = parser; grpc_chttp2_outstanding_ping *ping; while (p->byte != 8 && cur != end) { p->opaque_8bytes[p->byte] = *cur; cur++; p->byte++; } if (p->byte == 8) { GPR_ASSERT(is_last); if (p->is_ack) { for (ping = transport_parsing->pings.next; ping != &transport_parsing->pings; ping = ping->next) { if (0 == memcmp(p->opaque_8bytes, ping->id, 8)) { grpc_iomgr_add_delayed_callback(ping->on_recv, 1); } ping->next->prev = ping->prev; ping->prev->next = ping->next; gpr_free(ping); } } else { gpr_slice_buffer_add(&transport_parsing->qbuf, grpc_chttp2_ping_create(1, p->opaque_8bytes)); } } return GRPC_CHTTP2_PARSE_OK; } grpc-0.11.1/src/core/transport/chttp2/frame_goaway.h0000644000175000017500000000602712600663151022515 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H #include "src/core/transport/chttp2/frame.h" #include #include #include typedef enum { GRPC_CHTTP2_GOAWAY_LSI0, GRPC_CHTTP2_GOAWAY_LSI1, GRPC_CHTTP2_GOAWAY_LSI2, GRPC_CHTTP2_GOAWAY_LSI3, GRPC_CHTTP2_GOAWAY_ERR0, GRPC_CHTTP2_GOAWAY_ERR1, GRPC_CHTTP2_GOAWAY_ERR2, GRPC_CHTTP2_GOAWAY_ERR3, GRPC_CHTTP2_GOAWAY_DEBUG } grpc_chttp2_goaway_parse_state; typedef struct { grpc_chttp2_goaway_parse_state state; gpr_uint32 last_stream_id; gpr_uint32 error_code; char *debug_data; gpr_uint32 debug_length; gpr_uint32 debug_pos; } grpc_chttp2_goaway_parser; void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p); void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p); grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( grpc_chttp2_goaway_parser *parser, gpr_uint32 length, gpr_uint8 flags); grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code, gpr_slice debug_data, gpr_slice_buffer *slice_buffer); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H */ grpc-0.11.1/src/core/transport/chttp2/frame_rst_stream.h0000644000175000017500000000451212600663151023406 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H #include #include "src/core/transport/chttp2/frame.h" typedef struct { gpr_uint8 byte; gpr_uint8 reason_bytes[4]; } grpc_chttp2_rst_stream_parser; gpr_slice grpc_chttp2_rst_stream_create(gpr_uint32 stream_id, gpr_uint32 code); grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( grpc_chttp2_rst_stream_parser *parser, gpr_uint32 length, gpr_uint8 flags); grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H */ grpc-0.11.1/src/core/transport/chttp2/stream_encoder.h0000644000175000017500000001006612600663151023044 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_ENCODER_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_ENCODER_H #include "src/core/transport/chttp2/frame.h" #include "src/core/transport/metadata.h" #include "src/core/transport/stream_op.h" #include #include #include #define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256 #define GRPC_CHTTP2_HPACKC_NUM_VALUES 256 #define GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS (4096 / 32) typedef struct { gpr_uint32 filter_elems_sum; /* one before the lowest usable table index */ gpr_uint32 tail_remote_index; gpr_uint16 table_size; gpr_uint16 table_elems; /* filter tables for elems: this tables provides an approximate popularity count for particular hashes, and are used to determine whether a new literal should be added to the compression table or not. They track a single integer that counts how often a particular value has been seen. When that count reaches max (255), all values are halved. */ gpr_uint8 filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS]; /* metadata context */ grpc_mdctx *mdctx; /* the string 'grpc-timeout' */ grpc_mdstr *timeout_key_str; /* entry tables for keys & elems: these tables track values that have been seen and *may* be in the decompressor table */ grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; gpr_uint32 indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; gpr_uint32 indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; gpr_uint16 table_elem_size[GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]; } grpc_chttp2_hpack_compressor; void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c, grpc_mdctx *mdctx); void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c); /* select stream ops to be encoded, moving them from inops to outops, and moving subsequent ops in inops forward in the queue */ gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count, gpr_uint32 max_flow_controlled_bytes, grpc_stream_op_buffer *outops); /* encode stream ops to output */ void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof, gpr_uint32 stream_id, grpc_chttp2_hpack_compressor *compressor, gpr_slice_buffer *output); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_ENCODER_H */ grpc-0.11.1/src/core/transport/chttp2/frame.h0000644000175000017500000000525012600663151021143 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_H #include #include /* Common definitions for frame handling in the chttp2 transport */ typedef enum { GRPC_CHTTP2_PARSE_OK, GRPC_CHTTP2_STREAM_ERROR, GRPC_CHTTP2_CONNECTION_ERROR } grpc_chttp2_parse_error; /* defined in internal.h */ typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing; typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing; #define GRPC_CHTTP2_FRAME_DATA 0 #define GRPC_CHTTP2_FRAME_HEADER 1 #define GRPC_CHTTP2_FRAME_CONTINUATION 9 #define GRPC_CHTTP2_FRAME_RST_STREAM 3 #define GRPC_CHTTP2_FRAME_SETTINGS 4 #define GRPC_CHTTP2_FRAME_PING 6 #define GRPC_CHTTP2_FRAME_GOAWAY 7 #define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8 #define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1) #define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1 #define GRPC_CHTTP2_FLAG_ACK 1 #define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4 #define GRPC_CHTTP2_DATA_FLAG_PADDED 8 #define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_H */ grpc-0.11.1/src/core/transport/chttp2/varint.c0000644000175000017500000000464212600663151021353 0ustar apollockapollock/* * * 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/transport/chttp2/varint.h" int grpc_chttp2_hpack_varint_length(gpr_uint32 tail_value) { if (tail_value < (1 << 7)) { return 2; } else if (tail_value < (1 << 14)) { return 3; } else if (tail_value < (1 << 21)) { return 4; } else if (tail_value < (1 << 28)) { return 5; } else { return 6; } } void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value, gpr_uint8* target, int tail_length) { switch (tail_length) { case 5: target[4] = (gpr_uint8)((tail_value >> 28) | 0x80); case 4: target[3] = (gpr_uint8)((tail_value >> 21) | 0x80); case 3: target[2] = (gpr_uint8)((tail_value >> 14) | 0x80); case 2: target[1] = (gpr_uint8)((tail_value >> 7) | 0x80); case 1: target[0] = (gpr_uint8)((tail_value) | 0x80); } target[tail_length - 1] &= 0x7f; } grpc-0.11.1/src/core/transport/chttp2/bin_encoder.h0000644000175000017500000000457412600663151022330 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H #include /* base64 encode a slice. Returns a new slice, does not take ownership of the input */ gpr_slice grpc_chttp2_base64_encode(gpr_slice input); /* Compress a slice with the static huffman encoder detailed in the hpack standard. Returns a new slice, does not take ownership of the input */ gpr_slice grpc_chttp2_huffman_compress(gpr_slice input); /* equivalent to: gpr_slice x = grpc_chttp2_base64_encode(input); gpr_slice y = grpc_chttp2_huffman_compress(x); gpr_slice_unref(x); return y; */ gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input); int grpc_is_binary_header(const char *key, size_t length); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H */ grpc-0.11.1/src/core/transport/chttp2/incoming_metadata.c0000644000175000017500000001516712600663151023517 0ustar apollockapollock/* * * 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/transport/chttp2/incoming_metadata.h" #include #include "src/core/transport/chttp2/internal.h" #include #include void grpc_chttp2_incoming_metadata_buffer_init( grpc_chttp2_incoming_metadata_buffer *buffer) { buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } void grpc_chttp2_incoming_metadata_buffer_destroy( grpc_chttp2_incoming_metadata_buffer *buffer) { size_t i; for (i = 0; i < buffer->count; i++) { GRPC_MDELEM_UNREF(buffer->elems[i].md); } gpr_free(buffer->elems); } void grpc_chttp2_incoming_metadata_buffer_add( grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) { if (buffer->capacity == buffer->count) { buffer->capacity = GPR_MAX(8, 2 * buffer->capacity); buffer->elems = gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity); } buffer->elems[buffer->count++].md = elem; } void grpc_chttp2_incoming_metadata_buffer_set_deadline( grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) { buffer->deadline = deadline; } void grpc_chttp2_incoming_metadata_live_op_buffer_end( grpc_chttp2_incoming_metadata_live_op_buffer *buffer) { gpr_free(buffer->elems); buffer->elems = NULL; } void grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into( grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb) { grpc_metadata_batch b; b.list.head = NULL; /* Store away the last element of the list, so that in patch_metadata_ops we can reconstitute the list. We can't do list building here as later incoming metadata may reallocate the underlying array. */ b.list.tail = (void *)(gpr_intptr)buffer->count; b.garbage.head = b.garbage.tail = NULL; b.deadline = buffer->deadline; buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); grpc_sopb_add_metadata(sopb, b); } void grpc_chttp2_incoming_metadata_buffer_swap( grpc_chttp2_incoming_metadata_buffer *a, grpc_chttp2_incoming_metadata_buffer *b) { GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, *a, *b); } void grpc_incoming_metadata_buffer_move_to_referencing_sopb( grpc_chttp2_incoming_metadata_buffer *src, grpc_chttp2_incoming_metadata_buffer *dst, grpc_stream_op_buffer *sopb) { size_t delta; size_t i; dst->deadline = gpr_time_min(src->deadline, dst->deadline); if (src->count == 0) { return; } if (dst->count == 0) { grpc_chttp2_incoming_metadata_buffer_swap(src, dst); return; } delta = dst->count; if (dst->capacity < src->count + dst->count) { dst->capacity = GPR_MAX(dst->capacity * 2, src->count + dst->count); dst->elems = gpr_realloc(dst->elems, dst->capacity * sizeof(*dst->elems)); } memcpy(dst->elems + dst->count, src->elems, src->count * sizeof(*src->elems)); dst->count += src->count; for (i = 0; i < sopb->nops; i++) { if (sopb->ops[i].type != GRPC_OP_METADATA) continue; sopb->ops[i].data.metadata.list.tail = (void *)(delta + (gpr_intptr)sopb->ops[i].data.metadata.list.tail); } src->count = 0; } void grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op( grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb, grpc_chttp2_incoming_metadata_live_op_buffer *live_op_buffer) { grpc_stream_op *ops = sopb->ops; size_t nops = sopb->nops; size_t i; size_t j; size_t mdidx = 0; size_t last_mdidx; int found_metadata = 0; /* rework the array of metadata into a linked list, making use of the breadcrumbs we left in metadata batches during add_metadata_batch */ for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; found_metadata = 1; /* we left a breadcrumb indicating where the end of this list is, and since we add sequentially, we know from the end of the last segment where this segment begins */ last_mdidx = (size_t)(gpr_intptr)(op->data.metadata.list.tail); GPR_ASSERT(last_mdidx > mdidx); GPR_ASSERT(last_mdidx <= buffer->count); /* turn the array into a doubly linked list */ op->data.metadata.list.head = &buffer->elems[mdidx]; op->data.metadata.list.tail = &buffer->elems[last_mdidx - 1]; for (j = mdidx + 1; j < last_mdidx; j++) { buffer->elems[j].prev = &buffer->elems[j - 1]; buffer->elems[j - 1].next = &buffer->elems[j]; } buffer->elems[mdidx].prev = NULL; buffer->elems[last_mdidx - 1].next = NULL; /* track where we're up to */ mdidx = last_mdidx; } if (found_metadata) { live_op_buffer->elems = buffer->elems; if (mdidx != buffer->count) { /* we have a partially read metadata batch still in incoming_metadata */ size_t new_count = buffer->count - mdidx; size_t copy_bytes = sizeof(*buffer->elems) * new_count; GPR_ASSERT(mdidx < buffer->count); buffer->elems = gpr_malloc(copy_bytes); memcpy(live_op_buffer->elems + mdidx, buffer->elems, copy_bytes); buffer->count = buffer->capacity = new_count; } else { buffer->elems = NULL; buffer->count = 0; buffer->capacity = 0; } } } grpc-0.11.1/src/core/transport/chttp2/alpn.h0000644000175000017500000000413412600663151021003 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_ALPN_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_ALPN_H #include /* Retuns 1 if the version is supported, 0 otherwise. */ int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size); /* Returns the number of protocol versions to advertise */ size_t grpc_chttp2_num_alpn_versions(void); /* Returns the protocol version at index i (0 <= i < * grpc_chttp2_num_alpn_versions()) */ const char *grpc_chttp2_get_alpn_version_index(size_t i); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_ALPN_H */ grpc-0.11.1/src/core/transport/chttp2/status_conversion.c0000644000175000017500000000727212600663151023642 0ustar apollockapollock/* * * 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/transport/chttp2/status_conversion.h" int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) { switch (status) { case GRPC_STATUS_OK: return GRPC_CHTTP2_NO_ERROR; case GRPC_STATUS_CANCELLED: return GRPC_CHTTP2_CANCEL; case GRPC_STATUS_RESOURCE_EXHAUSTED: return GRPC_CHTTP2_ENHANCE_YOUR_CALM; case GRPC_STATUS_PERMISSION_DENIED: return GRPC_CHTTP2_INADEQUATE_SECURITY; case GRPC_STATUS_UNAVAILABLE: return GRPC_CHTTP2_REFUSED_STREAM; default: return GRPC_CHTTP2_INTERNAL_ERROR; } } grpc_status_code grpc_chttp2_http2_error_to_grpc_status( grpc_chttp2_error_code error) { switch (error) { case GRPC_CHTTP2_NO_ERROR: /* should never be received */ return GRPC_STATUS_INTERNAL; case GRPC_CHTTP2_CANCEL: return GRPC_STATUS_CANCELLED; case GRPC_CHTTP2_ENHANCE_YOUR_CALM: return GRPC_STATUS_RESOURCE_EXHAUSTED; case GRPC_CHTTP2_INADEQUATE_SECURITY: return GRPC_STATUS_PERMISSION_DENIED; case GRPC_CHTTP2_REFUSED_STREAM: return GRPC_STATUS_UNAVAILABLE; default: return GRPC_STATUS_INTERNAL; } } grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) { switch (status) { /* these HTTP2 status codes are called out explicitly in status.proto */ case 200: return GRPC_STATUS_OK; case 400: return GRPC_STATUS_INVALID_ARGUMENT; case 401: return GRPC_STATUS_UNAUTHENTICATED; case 403: return GRPC_STATUS_PERMISSION_DENIED; case 404: return GRPC_STATUS_NOT_FOUND; case 409: return GRPC_STATUS_ABORTED; case 412: return GRPC_STATUS_FAILED_PRECONDITION; case 429: return GRPC_STATUS_RESOURCE_EXHAUSTED; case 499: return GRPC_STATUS_CANCELLED; case 500: return GRPC_STATUS_UNKNOWN; case 501: return GRPC_STATUS_UNIMPLEMENTED; case 503: return GRPC_STATUS_UNAVAILABLE; case 504: return GRPC_STATUS_DEADLINE_EXCEEDED; /* everything else is unknown */ default: return GRPC_STATUS_UNKNOWN; } } int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) { return 200; } grpc-0.11.1/src/core/transport/chttp2/bin_encoder.c0000644000175000017500000001626512600663151022323 0ustar apollockapollock/* * * 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/transport/chttp2/bin_encoder.h" #include #include "src/core/transport/chttp2/huffsyms.h" #include static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; typedef struct { gpr_uint16 bits; gpr_uint8 length; } b64_huff_sym; static const b64_huff_sym huff_alphabet[64] = { {0x21, 6}, {0x5d, 7}, {0x5e, 7}, {0x5f, 7}, {0x60, 7}, {0x61, 7}, {0x62, 7}, {0x63, 7}, {0x64, 7}, {0x65, 7}, {0x66, 7}, {0x67, 7}, {0x68, 7}, {0x69, 7}, {0x6a, 7}, {0x6b, 7}, {0x6c, 7}, {0x6d, 7}, {0x6e, 7}, {0x6f, 7}, {0x70, 7}, {0x71, 7}, {0x72, 7}, {0xfc, 8}, {0x73, 7}, {0xfd, 8}, {0x3, 5}, {0x23, 6}, {0x4, 5}, {0x24, 6}, {0x5, 5}, {0x25, 6}, {0x26, 6}, {0x27, 6}, {0x6, 5}, {0x74, 7}, {0x75, 7}, {0x28, 6}, {0x29, 6}, {0x2a, 6}, {0x7, 5}, {0x2b, 6}, {0x76, 7}, {0x2c, 6}, {0x8, 5}, {0x9, 5}, {0x2d, 6}, {0x77, 7}, {0x78, 7}, {0x79, 7}, {0x7a, 7}, {0x7b, 7}, {0x0, 5}, {0x1, 5}, {0x2, 5}, {0x19, 6}, {0x1a, 6}, {0x1b, 6}, {0x1c, 6}, {0x1d, 6}, {0x1e, 6}, {0x1f, 6}, {0x7fb, 11}, {0x18, 6}}; static const gpr_uint8 tail_xtra[3] = {0, 2, 3}; gpr_slice grpc_chttp2_base64_encode(gpr_slice input) { size_t input_length = GPR_SLICE_LENGTH(input); size_t input_triplets = input_length / 3; size_t tail_case = input_length % 3; size_t output_length = input_triplets * 4 + tail_xtra[tail_case]; gpr_slice output = gpr_slice_malloc(output_length); gpr_uint8 *in = GPR_SLICE_START_PTR(input); gpr_uint8 *out = GPR_SLICE_START_PTR(output); size_t i; /* encode full triplets */ for (i = 0; i < input_triplets; i++) { out[0] = alphabet[in[0] >> 2]; out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; out[2] = alphabet[((in[1] & 0xf) << 2) | (in[2] >> 6)]; out[3] = alphabet[in[2] & 0x3f]; out += 4; in += 3; } /* encode the remaining bytes */ switch (tail_case) { case 0: break; case 1: out[0] = alphabet[in[0] >> 2]; out[1] = alphabet[(in[0] & 0x3) << 4]; out += 2; in += 1; break; case 2: out[0] = alphabet[in[0] >> 2]; out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; out[2] = alphabet[(in[1] & 0xf) << 2]; out += 3; in += 2; break; } GPR_ASSERT(out == GPR_SLICE_END_PTR(output)); GPR_ASSERT(in == GPR_SLICE_END_PTR(input)); return output; } gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) { size_t nbits; gpr_uint8 *in; gpr_uint8 *out; gpr_slice output; gpr_uint32 temp = 0; gpr_uint32 temp_length = 0; nbits = 0; for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) { nbits += grpc_chttp2_huffsyms[*in].length; } output = gpr_slice_malloc(nbits / 8 + (nbits % 8 != 0)); out = GPR_SLICE_START_PTR(output); for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) { int sym = *in; temp <<= grpc_chttp2_huffsyms[sym].length; temp |= grpc_chttp2_huffsyms[sym].bits; temp_length += grpc_chttp2_huffsyms[sym].length; while (temp_length > 8) { temp_length -= 8; *out++ = temp >> temp_length; } } if (temp_length) { *out++ = (temp << (8 - temp_length)) | (0xff >> temp_length); } GPR_ASSERT(out == GPR_SLICE_END_PTR(output)); return output; } typedef struct { gpr_uint32 temp; gpr_uint32 temp_length; gpr_uint8 *out; } huff_out; static void enc_flush_some(huff_out *out) { while (out->temp_length > 8) { out->temp_length -= 8; *out->out++ = out->temp >> out->temp_length; } } static void enc_add2(huff_out *out, gpr_uint8 a, gpr_uint8 b) { b64_huff_sym sa = huff_alphabet[a]; b64_huff_sym sb = huff_alphabet[b]; out->temp = (out->temp << (sa.length + sb.length)) | (sa.bits << sb.length) | sb.bits; out->temp_length += sa.length + sb.length; enc_flush_some(out); } static void enc_add1(huff_out *out, gpr_uint8 a) { b64_huff_sym sa = huff_alphabet[a]; out->temp = (out->temp << sa.length) | sa.bits; out->temp_length += sa.length; enc_flush_some(out); } gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input) { size_t input_length = GPR_SLICE_LENGTH(input); size_t input_triplets = input_length / 3; size_t tail_case = input_length % 3; size_t output_syms = input_triplets * 4 + tail_xtra[tail_case]; size_t max_output_bits = 11 * output_syms; size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0); gpr_slice output = gpr_slice_malloc(max_output_length); gpr_uint8 *in = GPR_SLICE_START_PTR(input); gpr_uint8 *start_out = GPR_SLICE_START_PTR(output); huff_out out; size_t i; out.temp = 0; out.temp_length = 0; out.out = start_out; /* encode full triplets */ for (i = 0; i < input_triplets; i++) { enc_add2(&out, in[0] >> 2, ((in[0] & 0x3) << 4) | (in[1] >> 4)); enc_add2(&out, ((in[1] & 0xf) << 2) | (in[2] >> 6), in[2] & 0x3f); in += 3; } /* encode the remaining bytes */ switch (tail_case) { case 0: break; case 1: enc_add2(&out, in[0] >> 2, (in[0] & 0x3) << 4); in += 1; break; case 2: enc_add2(&out, in[0] >> 2, ((in[0] & 0x3) << 4) | (in[1] >> 4)); enc_add1(&out, (in[1] & 0xf) << 2); in += 2; break; } if (out.temp_length) { *out.out++ = (out.temp << (8 - out.temp_length)) | (0xff >> out.temp_length); } GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output)); GPR_SLICE_SET_LENGTH(output, out.out - start_out); GPR_ASSERT(in == GPR_SLICE_END_PTR(input)); return output; } int grpc_is_binary_header(const char *key, size_t length) { if (length < 5) return 0; return 0 == memcmp(key + length - 4, "-bin", 4); } grpc-0.11.1/src/core/transport/chttp2/writing.c0000644000175000017500000002513012600663151021526 0ustar apollockapollock/* * * 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/transport/chttp2/internal.h" #include "src/core/transport/chttp2/http2_errors.h" #include static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing); int grpc_chttp2_unlocking_check_writes( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_writing *stream_writing; grpc_chttp2_stream_global *first_reinserted_stream = NULL; gpr_uint32 window_delta; /* simple writes are queued to qbuf, and flushed here */ gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); GPR_ASSERT(transport_global->qbuf.count == 0); if (transport_global->dirtied_local_settings && !transport_global->sent_local_settings) { gpr_slice_buffer_add( &transport_writing->outbuf, grpc_chttp2_settings_create( transport_global->settings[GRPC_SENT_SETTINGS], transport_global->settings[GRPC_LOCAL_SETTINGS], transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); transport_global->force_send_settings = 0; transport_global->dirtied_local_settings = 0; transport_global->sent_local_settings = 1; } /* for each grpc_chttp2_stream that's become writable, frame it's data (according to available window sizes) and add to the output buffer */ while (grpc_chttp2_list_pop_writable_stream( transport_global, transport_writing, &stream_global, &stream_writing)) { if (stream_global == first_reinserted_stream) { /* prevent infinite loop */ grpc_chttp2_list_add_first_writable_stream(transport_global, stream_global); break; } stream_writing->id = stream_global->id; stream_writing->send_closed = GRPC_DONT_SEND_CLOSED; if (stream_global->outgoing_sopb) { window_delta = grpc_chttp2_preencode(stream_global->outgoing_sopb->ops, &stream_global->outgoing_sopb->nops, GPR_MIN(transport_global->outgoing_window, stream_global->outgoing_window), &stream_writing->sopb); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "write", transport_global, outgoing_window, -(gpr_int64)window_delta); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, outgoing_window, -(gpr_int64)window_delta); transport_global->outgoing_window -= window_delta; stream_global->outgoing_window -= window_delta; if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE && stream_global->outgoing_sopb->nops == 0) { if (!transport_global->is_client && !stream_global->read_closed) { stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM; } else { stream_writing->send_closed = GRPC_SEND_CLOSED; } } if (stream_global->outgoing_window > 0 && stream_global->outgoing_sopb->nops != 0) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); if (first_reinserted_stream == NULL && transport_global->outgoing_window == 0) { first_reinserted_stream = stream_global; } } } if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) { GPR_ASSERT(stream_writing->announce_window == 0); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "write", transport_writing, stream_writing, announce_window, stream_global->unannounced_incoming_window); stream_writing->announce_window = stream_global->unannounced_incoming_window; GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "write", transport_global, stream_global, incoming_window, stream_global->unannounced_incoming_window); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "write", transport_global, stream_global, unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window); stream_global->incoming_window += stream_global->unannounced_incoming_window; stream_global->unannounced_incoming_window = 0; grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); stream_global->writing_now |= GRPC_CHTTP2_WRITING_WINDOW; } if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { stream_global->writing_now |= GRPC_CHTTP2_WRITING_DATA; } if (stream_global->writing_now != 0) { grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); } } /* if the grpc_chttp2_transport is ready to send a window update, do so here also; 3/4 is a magic number that will likely get tuned soon */ if (transport_global->incoming_window < transport_global->connection_window_target * 3 / 4) { window_delta = transport_global->connection_window_target - transport_global->incoming_window; gpr_slice_buffer_add(&transport_writing->outbuf, grpc_chttp2_window_update_create(0, window_delta)); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global, incoming_window, window_delta); transport_global->incoming_window += window_delta; } return transport_writing->outbuf.count > 0 || grpc_chttp2_list_have_writing_streams(transport_writing); } void grpc_chttp2_perform_writes( grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint) { GPR_ASSERT(transport_writing->outbuf.count > 0 || grpc_chttp2_list_have_writing_streams(transport_writing)); finalize_outbuf(transport_writing); GPR_ASSERT(transport_writing->outbuf.count > 0); GPR_ASSERT(endpoint); switch (grpc_endpoint_write(endpoint, &transport_writing->outbuf, &transport_writing->done_cb)) { case GRPC_ENDPOINT_DONE: grpc_chttp2_terminate_writing(transport_writing, 1); break; case GRPC_ENDPOINT_ERROR: grpc_chttp2_terminate_writing(transport_writing, 0); break; case GRPC_ENDPOINT_PENDING: break; } } static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_writing *stream_writing; while ( grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) { if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops, stream_writing->send_closed != GRPC_DONT_SEND_CLOSED, stream_writing->id, &transport_writing->hpack_compressor, &transport_writing->outbuf); stream_writing->sopb.nops = 0; } if (stream_writing->announce_window > 0) { gpr_slice_buffer_add( &transport_writing->outbuf, grpc_chttp2_window_update_create(stream_writing->id, stream_writing->announce_window)); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "write", transport_writing, stream_writing, announce_window, -(gpr_int64)stream_writing->announce_window); stream_writing->announce_window = 0; } if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) { gpr_slice_buffer_add(&transport_writing->outbuf, grpc_chttp2_rst_stream_create(stream_writing->id, GRPC_CHTTP2_NO_ERROR)); } grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); } } void grpc_chttp2_cleanup_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_writing *stream_writing; grpc_chttp2_stream_global *stream_global; while (grpc_chttp2_list_pop_written_stream( transport_global, transport_writing, &stream_global, &stream_writing)) { GPR_ASSERT(stream_global->writing_now != 0); if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE; if (!transport_global->is_client) { stream_global->read_closed = 1; } } if (stream_global->writing_now & GRPC_CHTTP2_WRITING_DATA) { if (stream_global->outgoing_sopb != NULL && stream_global->outgoing_sopb->nops == 0) { GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_QUEUED_CLOSE); stream_global->outgoing_sopb = NULL; grpc_chttp2_schedule_closure(transport_global, stream_global->send_done_closure, 1); } } stream_global->writing_now = 0; grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); } grpc-0.11.1/src/core/transport/chttp2/hpack_table.c0000644000175000017500000001725012600663151022304 0ustar apollockapollock/* * * 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/transport/chttp2/hpack_table.h" #include #include #include #include "src/core/support/murmur_hash.h" static struct { const char *key; const char *value; } static_table[] = { /* 0: */ {NULL, NULL}, /* 1: */ {":authority", ""}, /* 2: */ {":method", "GET"}, /* 3: */ {":method", "POST"}, /* 4: */ {":path", "/"}, /* 5: */ {":path", "/index.html"}, /* 6: */ {":scheme", "http"}, /* 7: */ {":scheme", "https"}, /* 8: */ {":status", "200"}, /* 9: */ {":status", "204"}, /* 10: */ {":status", "206"}, /* 11: */ {":status", "304"}, /* 12: */ {":status", "400"}, /* 13: */ {":status", "404"}, /* 14: */ {":status", "500"}, /* 15: */ {"accept-charset", ""}, /* 16: */ {"accept-encoding", "gzip, deflate"}, /* 17: */ {"accept-language", ""}, /* 18: */ {"accept-ranges", ""}, /* 19: */ {"accept", ""}, /* 20: */ {"access-control-allow-origin", ""}, /* 21: */ {"age", ""}, /* 22: */ {"allow", ""}, /* 23: */ {"authorization", ""}, /* 24: */ {"cache-control", ""}, /* 25: */ {"content-disposition", ""}, /* 26: */ {"content-encoding", ""}, /* 27: */ {"content-language", ""}, /* 28: */ {"content-length", ""}, /* 29: */ {"content-location", ""}, /* 30: */ {"content-range", ""}, /* 31: */ {"content-type", ""}, /* 32: */ {"cookie", ""}, /* 33: */ {"date", ""}, /* 34: */ {"etag", ""}, /* 35: */ {"expect", ""}, /* 36: */ {"expires", ""}, /* 37: */ {"from", ""}, /* 38: */ {"host", ""}, /* 39: */ {"if-match", ""}, /* 40: */ {"if-modified-since", ""}, /* 41: */ {"if-none-match", ""}, /* 42: */ {"if-range", ""}, /* 43: */ {"if-unmodified-since", ""}, /* 44: */ {"last-modified", ""}, /* 45: */ {"link", ""}, /* 46: */ {"location", ""}, /* 47: */ {"max-forwards", ""}, /* 48: */ {"proxy-authenticate", ""}, /* 49: */ {"proxy-authorization", ""}, /* 50: */ {"range", ""}, /* 51: */ {"referer", ""}, /* 52: */ {"refresh", ""}, /* 53: */ {"retry-after", ""}, /* 54: */ {"server", ""}, /* 55: */ {"set-cookie", ""}, /* 56: */ {"strict-transport-security", ""}, /* 57: */ {"transfer-encoding", ""}, /* 58: */ {"user-agent", ""}, /* 59: */ {"vary", ""}, /* 60: */ {"via", ""}, /* 61: */ {"www-authenticate", ""}, }; void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) { size_t i; memset(tbl, 0, sizeof(*tbl)); tbl->mdctx = mdctx; tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE; for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { tbl->static_ents[i - 1] = grpc_mdelem_from_strings( mdctx, static_table[i].key, static_table[i].value); } } void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) { size_t i; for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { GRPC_MDELEM_UNREF(tbl->static_ents[i]); } for (i = 0; i < tbl->num_ents; i++) { GRPC_MDELEM_UNREF( tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]); } } grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, gpr_uint32 index) { /* Static table comes first, just return an entry from it */ if (index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) { return tbl->static_ents[index - 1]; } /* Otherwise, find the value in the list of valid entries */ index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1); if (index < tbl->num_ents) { gpr_uint32 offset = (tbl->num_ents - 1 - index + tbl->first_ent) % GRPC_CHTTP2_MAX_TABLE_COUNT; return tbl->ents[offset]; } /* Invalid entry: return error */ return NULL; } /* Evict one element from the table */ static void evict1(grpc_chttp2_hptbl *tbl) { grpc_mdelem *first_ent = tbl->ents[tbl->first_ent]; tbl->mem_used -= GPR_SLICE_LENGTH(first_ent->key->slice) + GPR_SLICE_LENGTH(first_ent->value->slice) + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; tbl->first_ent = (tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT; tbl->num_ents--; GRPC_MDELEM_UNREF(first_ent); } void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { /* determine how many bytes of buffer this entry represents */ gpr_uint16 elem_bytes = GPR_SLICE_LENGTH(md->key->slice) + GPR_SLICE_LENGTH(md->value->slice) + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; /* we can't add elements bigger than the max table size */ if (elem_bytes > tbl->max_bytes) { /* HPACK draft 10 section 4.4 states: * If the size of the new entry is less than or equal to the maximum * size, that entry is added to the table. It is not an error to * attempt to add an entry that is larger than the maximum size; an * attempt to add an entry larger than the entire table causes * the table * to be emptied of all existing entries, and results in an * empty table. */ while (tbl->num_ents) { evict1(tbl); } return; } /* evict entries to ensure no overflow */ while (elem_bytes > tbl->max_bytes - tbl->mem_used) { evict1(tbl); } /* copy the finalized entry in */ tbl->ents[tbl->last_ent] = md; /* update accounting values */ tbl->last_ent = (tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT; tbl->num_ents++; tbl->mem_used += elem_bytes; } grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { grpc_chttp2_hptbl_find_result r = {0, 0}; int i; /* See if the string is in the static table */ for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { grpc_mdelem *ent = tbl->static_ents[i]; if (md->key != ent->key) continue; r.index = i + 1; r.has_value = md->value == ent->value; if (r.has_value) return r; } /* Scan the dynamic table */ for (i = 0; i < tbl->num_ents; i++) { int idx = tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY; grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]; if (md->key != ent->key) continue; r.index = idx; r.has_value = md->value == ent->value; if (r.has_value) return r; } return r; } grpc-0.11.1/src/core/transport/chttp2/frame_settings.h0000644000175000017500000000750412600663151023067 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H #include #include #include "src/core/transport/chttp2/frame.h" typedef enum { GRPC_CHTTP2_SPS_ID0, GRPC_CHTTP2_SPS_ID1, GRPC_CHTTP2_SPS_VAL0, GRPC_CHTTP2_SPS_VAL1, GRPC_CHTTP2_SPS_VAL2, GRPC_CHTTP2_SPS_VAL3 } grpc_chttp2_settings_parse_state; /* The things HTTP/2 defines as connection level settings */ typedef enum { GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6, GRPC_CHTTP2_NUM_SETTINGS } grpc_chttp2_setting_id; typedef struct { grpc_chttp2_settings_parse_state state; gpr_uint32 *target_settings; gpr_uint8 is_ack; gpr_uint16 id; gpr_uint32 value; gpr_uint32 incoming_settings[GRPC_CHTTP2_NUM_SETTINGS]; } grpc_chttp2_settings_parser; typedef enum { GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE } grpc_chttp2_invalid_value_behavior; typedef struct { const char *name; gpr_uint32 default_value; gpr_uint32 min_value; gpr_uint32 max_value; grpc_chttp2_invalid_value_behavior invalid_value_behavior; } grpc_chttp2_setting_parameters; /* HTTP/2 mandated connection setting parameters */ extern const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; /* Create a settings frame by diffing old & new, and updating old to be new */ gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new, gpr_uint32 force_mask, size_t count); /* Create an ack settings frame */ gpr_slice grpc_chttp2_settings_ack_create(void); grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags, gpr_uint32 *settings); grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( void *parser, grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H */ grpc-0.11.1/src/core/transport/chttp2/alpn.c0000644000175000017500000000430012600663151020771 0ustar apollockapollock/* * * 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/transport/chttp2/alpn.h" #include #include /* in order of preference */ static const char *const supported_versions[] = {"h2"}; int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) { size_t i; for (i = 0; i < GPR_ARRAY_SIZE(supported_versions); i++) { if (!strncmp(version, supported_versions[i], size)) return 1; } return 0; } size_t grpc_chttp2_num_alpn_versions(void) { return GPR_ARRAY_SIZE(supported_versions); } const char *grpc_chttp2_get_alpn_version_index(size_t i) { GPR_ASSERT(i < GPR_ARRAY_SIZE(supported_versions)); return supported_versions[i]; } grpc-0.11.1/src/core/httpcli/0000755000175000017500000000000012600663151016105 5ustar apollockapollockgrpc-0.11.1/src/core/httpcli/parser.h0000644000175000017500000000460112600663151017553 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H #define GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H #include "src/core/httpcli/httpcli.h" #include #include typedef enum { GRPC_HTTPCLI_INITIAL_RESPONSE, GRPC_HTTPCLI_HEADERS, GRPC_HTTPCLI_BODY } grpc_httpcli_parser_state; typedef struct { grpc_httpcli_parser_state state; grpc_httpcli_response r; size_t body_capacity; size_t hdr_capacity; gpr_uint8 cur_line[GRPC_HTTPCLI_MAX_HEADER_LENGTH]; size_t cur_line_length; } grpc_httpcli_parser; void grpc_httpcli_parser_init(grpc_httpcli_parser *parser); void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser); int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice); int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser); #endif /* GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H */ grpc-0.11.1/src/core/httpcli/httpcli_security_connector.c0000644000175000017500000001536612600663151023734 0ustar apollockapollock/* * * 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/httpcli/httpcli.h" #include #include "src/core/security/secure_transport_setup.h" #include "src/core/support/string.h" #include #include #include #include "src/core/tsi/ssl_transport_security.h" typedef struct { grpc_channel_security_connector base; tsi_ssl_handshaker_factory *handshaker_factory; char *secure_peer_name; } grpc_httpcli_ssl_channel_security_connector; static void httpcli_ssl_destroy(grpc_security_connector *sc) { grpc_httpcli_ssl_channel_security_connector *c = (grpc_httpcli_ssl_channel_security_connector *)sc; if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); gpr_free(sc); } static grpc_security_status httpcli_ssl_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_httpcli_ssl_channel_security_connector *c = (grpc_httpcli_ssl_channel_security_connector *)sc; tsi_result result = TSI_OK; if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR; result = tsi_ssl_handshaker_factory_create_handshaker( c->handshaker_factory, c->secure_peer_name, handshaker); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", tsi_result_to_string(result)); return GRPC_SECURITY_ERROR; } return GRPC_SECURITY_OK; } static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { grpc_httpcli_ssl_channel_security_connector *c = (grpc_httpcli_ssl_channel_security_connector *)sc; grpc_security_status status = GRPC_SECURITY_OK; /* Check the peer name. */ if (c->secure_peer_name != NULL && !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) { gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", c->secure_peer_name); status = GRPC_SECURITY_ERROR; } tsi_peer_destruct(&peer); return status; } static grpc_security_connector_vtable httpcli_ssl_vtable = { httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer}; static grpc_security_status httpcli_ssl_channel_security_connector_create( const unsigned char *pem_root_certs, size_t pem_root_certs_size, const char *secure_peer_name, grpc_channel_security_connector **sc) { tsi_result result = TSI_OK; grpc_httpcli_ssl_channel_security_connector *c; if (secure_peer_name != NULL && pem_root_certs == NULL) { gpr_log(GPR_ERROR, "Cannot assert a secure peer name without a trust root."); return GRPC_SECURITY_ERROR; } c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector)); memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.is_client_side = 1; c->base.base.vtable = &httpcli_ssl_vtable; if (secure_peer_name != NULL) { c->secure_peer_name = gpr_strdup(secure_peer_name); } result = tsi_create_ssl_client_handshaker_factory( NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL, 0, &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); httpcli_ssl_destroy(&c->base.base); *sc = NULL; return GRPC_SECURITY_ERROR; } *sc = &c->base; return GRPC_SECURITY_OK; } /* handshaker */ typedef struct { void (*func)(void *arg, grpc_endpoint *endpoint); void *arg; } on_done_closure; static void on_secure_transport_setup_done(void *rp, grpc_security_status status, grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint) { on_done_closure *c = rp; if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); c->func(c->arg, NULL); } else { c->func(c->arg, secure_endpoint); } gpr_free(c); } static void ssl_handshake(void *arg, grpc_endpoint *tcp, const char *host, void (*on_done)(void *arg, grpc_endpoint *endpoint)) { grpc_channel_security_connector *sc = NULL; const unsigned char *pem_root_certs = NULL; on_done_closure *c = gpr_malloc(sizeof(*c)); size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); if (pem_root_certs == NULL || pem_root_certs_size == 0) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); on_done(arg, NULL); gpr_free(c); return; } c->func = on_done; c->arg = arg; GPR_ASSERT(httpcli_ssl_channel_security_connector_create( pem_root_certs, pem_root_certs_size, host, &sc) == GRPC_SECURITY_OK); grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done, c); GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); } const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; grpc-0.11.1/src/core/httpcli/format_request.c0000644000175000017500000001027412600663151021315 0ustar apollockapollock/* * * 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/httpcli/format_request.h" #include #include #include #include "src/core/support/string.h" #include #include #include #include static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec *buf) { size_t i; gpr_strvec_add(buf, gpr_strdup(request->path)); gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n")); /* just in case some crazy server really expects HTTP/1.1 */ gpr_strvec_add(buf, gpr_strdup("Host: ")); gpr_strvec_add(buf, gpr_strdup(request->host)); gpr_strvec_add(buf, gpr_strdup("\r\n")); gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n")); gpr_strvec_add(buf, gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n")); /* user supplied headers */ for (i = 0; i < request->hdr_count; i++) { gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].key)); gpr_strvec_add(buf, gpr_strdup(": ")); gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].value)); gpr_strvec_add(buf, gpr_strdup("\r\n")); } } gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) { gpr_strvec out; char *flat; size_t flat_len; gpr_strvec_init(&out); gpr_strvec_add(&out, gpr_strdup("GET ")); fill_common_header(request, &out); gpr_strvec_add(&out, gpr_strdup("\r\n")); flat = gpr_strvec_flatten(&out, &flat_len); gpr_strvec_destroy(&out); return gpr_slice_new(flat, flat_len, gpr_free); } gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, const char *body_bytes, size_t body_size) { gpr_strvec out; char *tmp; size_t out_len; size_t i; gpr_strvec_init(&out); gpr_strvec_add(&out, gpr_strdup("POST ")); fill_common_header(request, &out); if (body_bytes) { gpr_uint8 has_content_type = 0; for (i = 0; i < request->hdr_count; i++) { if (strcmp(request->hdrs[i].key, "Content-Type") == 0) { has_content_type = 1; break; } } if (!has_content_type) { gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n")); } gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size); gpr_strvec_add(&out, tmp); } gpr_strvec_add(&out, gpr_strdup("\r\n")); tmp = gpr_strvec_flatten(&out, &out_len); gpr_strvec_destroy(&out); if (body_bytes) { tmp = gpr_realloc(tmp, out_len + body_size); memcpy(tmp + out_len, body_bytes, body_size); out_len += body_size; } return gpr_slice_new(tmp, out_len, gpr_free); } grpc-0.11.1/src/core/httpcli/httpcli.h0000644000175000017500000001522612600663151017733 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H #define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H #include #include #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/pollset_set.h" /* User agent this library reports */ #define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0" /* Maximum length of a header string of the form 'Key: Value\r\n' */ #define GRPC_HTTPCLI_MAX_HEADER_LENGTH 4096 /* A single header to be passed in a request */ typedef struct grpc_httpcli_header { char *key; char *value; } grpc_httpcli_header; /* Tracks in-progress http requests TODO(ctiller): allow caching and capturing multiple requests for the same content and combining them */ typedef struct grpc_httpcli_context { grpc_pollset_set pollset_set; } grpc_httpcli_context; typedef struct { const char *default_port; void (*handshake)(void *arg, grpc_endpoint *endpoint, const char *host, void (*on_done)(void *arg, grpc_endpoint *endpoint)); } grpc_httpcli_handshaker; extern const grpc_httpcli_handshaker grpc_httpcli_plaintext; extern const grpc_httpcli_handshaker grpc_httpcli_ssl; /* A request */ typedef struct grpc_httpcli_request { /* The host name to connect to */ char *host; /* The path of the resource to fetch */ char *path; /* Additional headers: count and key/values; the following are supplied automatically and MUST NOT be set here: Host, Connection, User-Agent */ size_t hdr_count; grpc_httpcli_header *hdrs; /* handshaker to use ssl for the request */ const grpc_httpcli_handshaker *handshaker; } grpc_httpcli_request; /* A response */ typedef struct grpc_httpcli_response { /* HTTP status code */ int status; /* Headers: count and key/values */ size_t hdr_count; grpc_httpcli_header *hdrs; /* Body: length and contents; contents are NOT null-terminated */ size_t body_length; char *body; } grpc_httpcli_response; /* Callback for grpc_httpcli_get and grpc_httpcli_post. */ typedef void (*grpc_httpcli_response_cb)(void *user_data, const grpc_httpcli_response *response); void grpc_httpcli_context_init(grpc_httpcli_context *context); void grpc_httpcli_context_destroy(grpc_httpcli_context *context); /* Asynchronously perform a HTTP GET. 'context' specifies the http context under which to do the get 'pollset' indicates a grpc_pollset that is interested in the result of the get - work on this pollset may be used to progress the get operation 'request' contains request parameters - these are caller owned and can be destroyed once the call returns 'deadline' contains a deadline for the request (or gpr_inf_future) 'on_response' is a callback to report results to (and 'user_data' is a user supplied pointer to pass to said call) */ void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset, const grpc_httpcli_request *request, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data); /* Asynchronously perform a HTTP POST. 'context' specifies the http context under which to do the post 'pollset' indicates a grpc_pollset that is interested in the result of the post - work on this pollset may be used to progress the post operation 'request' contains request parameters - these are caller owned and can be destroyed once the call returns 'body_bytes' and 'body_size' specify the payload for the post. When there is no body, pass in NULL as body_bytes. 'deadline' contains a deadline for the request (or gpr_inf_future) 'em' points to a caller owned event manager that must be alive for the lifetime of the request 'on_response' is a callback to report results to (and 'user_data' is a user supplied pointer to pass to said call) Does not support ?var1=val1&var2=val2 in the path. */ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset, const grpc_httpcli_request *request, const char *body_bytes, size_t body_size, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data); /* override functions return 1 if they handled the request, 0 otherwise */ typedef int (*grpc_httpcli_get_override)(const grpc_httpcli_request *request, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data); typedef int (*grpc_httpcli_post_override)(const grpc_httpcli_request *request, const char *body_bytes, size_t body_size, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data); void grpc_httpcli_set_override(grpc_httpcli_get_override get, grpc_httpcli_post_override post); #endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H */ grpc-0.11.1/src/core/httpcli/httpcli.c0000644000175000017500000002275612600663151017734 0ustar apollockapollock/* * * 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/iomgr/sockaddr.h" #include "src/core/httpcli/httpcli.h" #include #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/httpcli/format_request.h" #include "src/core/httpcli/parser.h" #include "src/core/support/string.h" #include #include #include typedef struct { gpr_slice request_text; grpc_httpcli_parser parser; grpc_resolved_addresses *addresses; size_t next_address; grpc_endpoint *ep; char *host; gpr_timespec deadline; int have_read_byte; const grpc_httpcli_handshaker *handshaker; grpc_httpcli_response_cb on_response; void *user_data; grpc_httpcli_context *context; grpc_pollset *pollset; grpc_iomgr_object iomgr_obj; gpr_slice_buffer incoming; gpr_slice_buffer outgoing; grpc_iomgr_closure on_read; grpc_iomgr_closure done_write; } internal_request; static grpc_httpcli_get_override g_get_override = NULL; static grpc_httpcli_post_override g_post_override = NULL; static void plaintext_handshake(void *arg, grpc_endpoint *endpoint, const char *host, void (*on_done)(void *arg, grpc_endpoint *endpoint)) { on_done(arg, endpoint); } const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http", plaintext_handshake}; void grpc_httpcli_context_init(grpc_httpcli_context *context) { grpc_pollset_set_init(&context->pollset_set); } void grpc_httpcli_context_destroy(grpc_httpcli_context *context) { grpc_pollset_set_destroy(&context->pollset_set); } static void next_address(internal_request *req); static void finish(internal_request *req, int success) { grpc_pollset_set_del_pollset(&req->context->pollset_set, req->pollset); req->on_response(req->user_data, success ? &req->parser.r : NULL); grpc_httpcli_parser_destroy(&req->parser); if (req->addresses != NULL) { grpc_resolved_addresses_destroy(req->addresses); } if (req->ep != NULL) { grpc_endpoint_destroy(req->ep); } gpr_slice_unref(req->request_text); gpr_free(req->host); grpc_iomgr_unregister_object(&req->iomgr_obj); gpr_slice_buffer_destroy(&req->incoming); gpr_slice_buffer_destroy(&req->outgoing); gpr_free(req); } static void on_read(void *user_data, int success); static void do_read(internal_request *req) { switch (grpc_endpoint_read(req->ep, &req->incoming, &req->on_read)) { case GRPC_ENDPOINT_DONE: on_read(req, 1); break; case GRPC_ENDPOINT_PENDING: break; case GRPC_ENDPOINT_ERROR: on_read(req, 0); break; } } static void on_read(void *user_data, int success) { internal_request *req = user_data; size_t i; for (i = 0; i < req->incoming.count; i++) { if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { req->have_read_byte = 1; if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) { finish(req, 0); return; } } } if (success) { do_read(req); } else if (!req->have_read_byte) { next_address(req); } else { finish(req, grpc_httpcli_parser_eof(&req->parser)); } } static void on_written(internal_request *req) { do_read(req); } static void done_write(void *arg, int success) { internal_request *req = arg; if (success) { on_written(req); } else { next_address(req); } } static void start_write(internal_request *req) { gpr_slice_ref(req->request_text); gpr_slice_buffer_add(&req->outgoing, req->request_text); switch (grpc_endpoint_write(req->ep, &req->outgoing, &req->done_write)) { case GRPC_ENDPOINT_DONE: on_written(req); break; case GRPC_ENDPOINT_PENDING: break; case GRPC_ENDPOINT_ERROR: finish(req, 0); break; } } static void on_handshake_done(void *arg, grpc_endpoint *ep) { internal_request *req = arg; if (!ep) { next_address(req); return; } req->ep = ep; start_write(req); } static void on_connected(void *arg, grpc_endpoint *tcp) { internal_request *req = arg; if (!tcp) { next_address(req); return; } req->handshaker->handshake(req, tcp, req->host, on_handshake_done); } static void next_address(internal_request *req) { grpc_resolved_address *addr; if (req->next_address == req->addresses->naddrs) { finish(req, 0); return; } addr = &req->addresses->addrs[req->next_address++]; grpc_tcp_client_connect(on_connected, req, &req->context->pollset_set, (struct sockaddr *)&addr->addr, addr->len, req->deadline); } static void on_resolved(void *arg, grpc_resolved_addresses *addresses) { internal_request *req = arg; if (!addresses) { finish(req, 0); return; } req->addresses = addresses; req->next_address = 0; next_address(req); } void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset, const grpc_httpcli_request *request, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data) { internal_request *req; char *name; if (g_get_override && g_get_override(request, deadline, on_response, user_data)) { return; } req = gpr_malloc(sizeof(internal_request)); memset(req, 0, sizeof(*req)); req->request_text = grpc_httpcli_format_get_request(request); grpc_httpcli_parser_init(&req->parser); req->on_response = on_response; req->user_data = user_data; req->deadline = deadline; req->handshaker = request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; grpc_iomgr_closure_init(&req->on_read, on_read, req); grpc_iomgr_closure_init(&req->done_write, done_write, req); gpr_slice_buffer_init(&req->incoming); gpr_slice_buffer_init(&req->outgoing); gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); req->host = gpr_strdup(request->host); grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset); grpc_resolve_address(request->host, req->handshaker->default_port, on_resolved, req); } void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset, const grpc_httpcli_request *request, const char *body_bytes, size_t body_size, gpr_timespec deadline, grpc_httpcli_response_cb on_response, void *user_data) { internal_request *req; char *name; if (g_post_override && g_post_override(request, body_bytes, body_size, deadline, on_response, user_data)) { return; } req = gpr_malloc(sizeof(internal_request)); memset(req, 0, sizeof(*req)); req->request_text = grpc_httpcli_format_post_request(request, body_bytes, body_size); grpc_httpcli_parser_init(&req->parser); req->on_response = on_response; req->user_data = user_data; req->deadline = deadline; req->handshaker = request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; grpc_iomgr_closure_init(&req->on_read, on_read, req); grpc_iomgr_closure_init(&req->done_write, done_write, req); gpr_slice_buffer_init(&req->incoming); gpr_slice_buffer_init(&req->outgoing); gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); req->host = gpr_strdup(request->host); grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset); grpc_resolve_address(request->host, req->handshaker->default_port, on_resolved, req); } void grpc_httpcli_set_override(grpc_httpcli_get_override get, grpc_httpcli_post_override post) { g_get_override = get; g_post_override = post; } grpc-0.11.1/src/core/httpcli/parser.c0000644000175000017500000001502712600663151017552 0ustar apollockapollock/* * * 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/httpcli/parser.h" #include #include #include #include static int handle_response_line(grpc_httpcli_parser *parser) { gpr_uint8 *beg = parser->cur_line; gpr_uint8 *cur = beg; gpr_uint8 *end = beg + parser->cur_line_length; if (cur == end || *cur++ != 'H') goto error; if (cur == end || *cur++ != 'T') goto error; if (cur == end || *cur++ != 'T') goto error; if (cur == end || *cur++ != 'P') goto error; if (cur == end || *cur++ != '/') goto error; if (cur == end || *cur++ != '1') goto error; if (cur == end || *cur++ != '.') goto error; if (cur == end || *cur < '0' || *cur++ > '1') goto error; if (cur == end || *cur++ != ' ') goto error; if (cur == end || *cur < '1' || *cur++ > '9') goto error; if (cur == end || *cur < '0' || *cur++ > '9') goto error; if (cur == end || *cur < '0' || *cur++ > '9') goto error; parser->r.status = (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); if (cur == end || *cur++ != ' ') goto error; /* we don't really care about the status code message */ return 1; error: gpr_log(GPR_ERROR, "Failed parsing response line"); return 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 int add_header(grpc_httpcli_parser *parser) { gpr_uint8 *beg = parser->cur_line; gpr_uint8 *cur = beg; gpr_uint8 *end = beg + parser->cur_line_length; grpc_httpcli_header hdr = {NULL, NULL}; GPR_ASSERT(cur != end); if (*cur == ' ' || *cur == '\t') { gpr_log(GPR_ERROR, "Continued header lines not supported yet"); goto error; } while (cur != end && *cur != ':') { cur++; } if (cur == end) { gpr_log(GPR_ERROR, "Didn't find ':' in header string"); goto error; } hdr.key = buf2str(beg, cur - beg); cur++; /* skip : */ while (cur != end && (*cur == ' ' || *cur == '\t')) { cur++; } hdr.value = buf2str(cur, end - cur - 2); if (parser->r.hdr_count == parser->hdr_capacity) { parser->hdr_capacity = GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2); parser->r.hdrs = gpr_realloc( parser->r.hdrs, parser->hdr_capacity * sizeof(*parser->r.hdrs)); } parser->r.hdrs[parser->r.hdr_count++] = hdr; return 1; error: gpr_free(hdr.key); gpr_free(hdr.value); return 0; } static int finish_line(grpc_httpcli_parser *parser) { switch (parser->state) { case GRPC_HTTPCLI_INITIAL_RESPONSE: if (!handle_response_line(parser)) { return 0; } parser->state = GRPC_HTTPCLI_HEADERS; break; case GRPC_HTTPCLI_HEADERS: if (parser->cur_line_length == 2) { parser->state = GRPC_HTTPCLI_BODY; break; } if (!add_header(parser)) { return 0; } break; case GRPC_HTTPCLI_BODY: gpr_log(GPR_ERROR, "should never reach here"); abort(); } parser->cur_line_length = 0; return 1; } static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) { switch (parser->state) { case GRPC_HTTPCLI_INITIAL_RESPONSE: case GRPC_HTTPCLI_HEADERS: if (parser->cur_line_length >= GRPC_HTTPCLI_MAX_HEADER_LENGTH) { gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", GRPC_HTTPCLI_MAX_HEADER_LENGTH); return 0; } parser->cur_line[parser->cur_line_length] = byte; parser->cur_line_length++; 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 finish_line(parser); } else { return 1; } gpr_log(GPR_ERROR, "should never reach here"); abort(); case GRPC_HTTPCLI_BODY: if (parser->r.body_length == parser->body_capacity) { parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2); parser->r.body = gpr_realloc((void *)parser->r.body, parser->body_capacity); } ((char *)parser->r.body)[parser->r.body_length] = byte; parser->r.body_length++; return 1; } gpr_log(GPR_ERROR, "should never reach here"); abort(); return 0; } void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) { memset(parser, 0, sizeof(*parser)); parser->state = GRPC_HTTPCLI_INITIAL_RESPONSE; parser->r.status = 500; } void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser) { size_t i; gpr_free(parser->r.body); for (i = 0; i < parser->r.hdr_count; i++) { gpr_free(parser->r.hdrs[i].key); gpr_free(parser->r.hdrs[i].value); } gpr_free(parser->r.hdrs); } int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice) { size_t i; for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) { return 0; } } return 1; } int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser) { return parser->state == GRPC_HTTPCLI_BODY; } grpc-0.11.1/src/core/httpcli/format_request.h0000644000175000017500000000405512600663151021322 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H #define GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H #include "src/core/httpcli/httpcli.h" #include gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request); gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, const char *body_bytes, size_t body_size); #endif /* GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H */ grpc-0.11.1/src/core/support/0000755000175000017500000000000012600663151016152 5ustar apollockapollockgrpc-0.11.1/src/core/support/histogram.c0000644000175000017500000001726712600663151020330 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include /* Histograms are stored with exponentially increasing bucket sizes. The first bucket is [0, m) where m = 1 + resolution Bucket n (n>=1) contains [m**n, m**(n+1)) There are sufficient buckets to reach max_bucket_start */ struct gpr_histogram { /* Sum of all values seen so far */ double sum; /* Sum of squares of all values seen so far */ double sum_of_squares; /* number of values seen so far */ double count; /* m in the description */ double multiplier; double one_on_log_multiplier; /* minimum value seen */ double min_seen; /* maximum value seen */ double max_seen; /* maximum representable value */ double max_possible; /* number of buckets */ size_t num_buckets; /* the buckets themselves */ gpr_uint32 *buckets; }; /* determine a bucket index given a value - does no bounds checking */ static size_t bucket_for_unchecked(gpr_histogram *h, double x) { return (size_t)(log(x) * h->one_on_log_multiplier); } /* bounds checked version of the above */ static size_t bucket_for(gpr_histogram *h, double x) { size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible)); GPR_ASSERT(bucket < h->num_buckets); return bucket; } /* at what value does a bucket start? */ static double bucket_start(gpr_histogram *h, double x) { return pow(h->multiplier, x); } gpr_histogram *gpr_histogram_create(double resolution, double max_bucket_start) { gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram)); GPR_ASSERT(resolution > 0.0); GPR_ASSERT(max_bucket_start > resolution); h->sum = 0.0; h->sum_of_squares = 0.0; h->multiplier = 1.0 + resolution; h->one_on_log_multiplier = 1.0 / log(1.0 + resolution); h->max_possible = max_bucket_start; h->count = 0.0; h->min_seen = max_bucket_start; h->max_seen = 0.0; h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1; GPR_ASSERT(h->num_buckets > 1); GPR_ASSERT(h->num_buckets < 100000000); h->buckets = gpr_malloc(sizeof(gpr_uint32) * h->num_buckets); memset(h->buckets, 0, sizeof(gpr_uint32) * h->num_buckets); return h; } void gpr_histogram_destroy(gpr_histogram *h) { gpr_free(h->buckets); gpr_free(h); } void gpr_histogram_add(gpr_histogram *h, double x) { h->sum += x; h->sum_of_squares += x * x; h->count++; if (x < h->min_seen) { h->min_seen = x; } if (x > h->max_seen) { h->max_seen = x; } h->buckets[bucket_for(h, x)]++; } int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) { if ((dst->num_buckets != src->num_buckets) || (dst->multiplier != src->multiplier)) { /* Fail because these histograms don't match */ return 0; } gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets, src->min_seen, src->max_seen, src->sum, src->sum_of_squares, src->count); return 1; } void gpr_histogram_merge_contents(gpr_histogram *dst, const gpr_uint32 *data, size_t data_count, double min_seen, double max_seen, double sum, double sum_of_squares, double count) { size_t i; GPR_ASSERT(dst->num_buckets == data_count); dst->sum += sum; dst->sum_of_squares += sum_of_squares; dst->count += count; if (min_seen < dst->min_seen) { dst->min_seen = min_seen; } if (max_seen > dst->max_seen) { dst->max_seen = max_seen; } for (i = 0; i < dst->num_buckets; i++) { dst->buckets[i] += data[i]; } } static double threshold_for_count_below(gpr_histogram *h, double count_below) { double count_so_far; double lower_bound; double upper_bound; size_t lower_idx; size_t upper_idx; if (h->count == 0) { return 0.0; } if (count_below <= 0) { return h->min_seen; } if (count_below >= h->count) { return h->max_seen; } /* find the lowest bucket that gets us above count_below */ count_so_far = 0.0; for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) { count_so_far += h->buckets[lower_idx]; if (count_so_far >= count_below) { break; } } if (count_so_far == count_below) { /* this bucket hits the threshold exactly... we should be midway through any run of zero values following the bucket */ for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) { if (h->buckets[upper_idx]) { break; } } return (bucket_start(h, (double)lower_idx) + bucket_start(h, (double)upper_idx)) / 2.0; } else { /* treat values as uniform throughout the bucket, and find where this value should lie */ lower_bound = bucket_start(h, (double)lower_idx); upper_bound = bucket_start(h, (double)(lower_idx + 1)); return GPR_CLAMP(upper_bound - (upper_bound - lower_bound) * (count_so_far - count_below) / h->buckets[lower_idx], h->min_seen, h->max_seen); } } double gpr_histogram_percentile(gpr_histogram *h, double percentile) { return threshold_for_count_below(h, h->count * percentile / 100.0); } double gpr_histogram_mean(gpr_histogram *h) { GPR_ASSERT(h->count); return h->sum / h->count; } double gpr_histogram_stddev(gpr_histogram *h) { return sqrt(gpr_histogram_variance(h)); } double gpr_histogram_variance(gpr_histogram *h) { if (h->count == 0) return 0.0; return (h->sum_of_squares * h->count - h->sum * h->sum) / (h->count * h->count); } double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; } double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; } double gpr_histogram_count(gpr_histogram *h) { return h->count; } double gpr_histogram_sum(gpr_histogram *h) { return h->sum; } double gpr_histogram_sum_of_squares(gpr_histogram *h) { return h->sum_of_squares; } const gpr_uint32 *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) { *size = h->num_buckets; return h->buckets; } grpc-0.11.1/src/core/support/env_win32.c0000644000175000017500000000425312600663151020134 0ustar apollockapollock/* * * 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 #ifdef GPR_WIN32 #include "src/core/support/env.h" #include "src/core/support/string.h" #include #include #include #include char *gpr_getenv(const char *name) { size_t size; char *result = NULL; char *duplicated; errno_t err; err = _dupenv_s(&result, &size, name); if (err) return NULL; duplicated = gpr_strdup(result); free(result); return duplicated; } void gpr_setenv(const char *name, const char *value) { errno_t res = _putenv_s(name, value); GPR_ASSERT(res == 0); } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/slice.c0000644000175000017500000002504012600663151017416 0ustar apollockapollock/* * * 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 #include #include #include gpr_slice gpr_empty_slice(void) { gpr_slice out; out.refcount = 0; out.data.inlined.length = 0; return out; } gpr_slice gpr_slice_ref(gpr_slice slice) { if (slice.refcount) { slice.refcount->ref(slice.refcount); } return slice; } void gpr_slice_unref(gpr_slice slice) { if (slice.refcount) { slice.refcount->unref(slice.refcount); } } /* gpr_slice_new support structures - we create a refcount object extended with the user provided data pointer & destroy function */ typedef struct new_slice_refcount { gpr_slice_refcount rc; gpr_refcount refs; void (*user_destroy)(void *); void *user_data; } new_slice_refcount; static void new_slice_ref(void *p) { new_slice_refcount *r = p; gpr_ref(&r->refs); } static void new_slice_unref(void *p) { new_slice_refcount *r = p; if (gpr_unref(&r->refs)) { r->user_destroy(r->user_data); gpr_free(r); } } gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) { gpr_slice slice; new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount)); gpr_ref_init(&rc->refs, 1); rc->rc.ref = new_slice_ref; rc->rc.unref = new_slice_unref; rc->user_destroy = destroy; rc->user_data = p; slice.refcount = &rc->rc; slice.data.refcounted.bytes = p; slice.data.refcounted.length = len; return slice; } /* gpr_slice_new_with_len support structures - we create a refcount object extended with the user provided data pointer & destroy function */ typedef struct new_with_len_slice_refcount { gpr_slice_refcount rc; gpr_refcount refs; void *user_data; size_t user_length; void (*user_destroy)(void *, size_t); } new_with_len_slice_refcount; static void new_with_len_ref(void *p) { new_with_len_slice_refcount *r = p; gpr_ref(&r->refs); } static void new_with_len_unref(void *p) { new_with_len_slice_refcount *r = p; if (gpr_unref(&r->refs)) { r->user_destroy(r->user_data, r->user_length); gpr_free(r); } } gpr_slice gpr_slice_new_with_len(void *p, size_t len, void (*destroy)(void *, size_t)) { gpr_slice slice; new_with_len_slice_refcount *rc = gpr_malloc(sizeof(new_with_len_slice_refcount)); gpr_ref_init(&rc->refs, 1); rc->rc.ref = new_with_len_ref; rc->rc.unref = new_with_len_unref; rc->user_destroy = destroy; rc->user_data = p; rc->user_length = len; slice.refcount = &rc->rc; slice.data.refcounted.bytes = p; slice.data.refcounted.length = len; return slice; } gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) { gpr_slice slice = gpr_slice_malloc(length); memcpy(GPR_SLICE_START_PTR(slice), source, length); return slice; } gpr_slice gpr_slice_from_copied_string(const char *source) { return gpr_slice_from_copied_buffer(source, strlen(source)); } typedef struct { gpr_slice_refcount base; gpr_refcount refs; } malloc_refcount; static void malloc_ref(void *p) { malloc_refcount *r = p; gpr_ref(&r->refs); } static void malloc_unref(void *p) { malloc_refcount *r = p; if (gpr_unref(&r->refs)) { gpr_free(r); } } gpr_slice gpr_slice_malloc(size_t length) { gpr_slice slice; if (length > sizeof(slice.data.inlined.bytes)) { /* Memory layout used by the slice created here: +-----------+----------------------------------------------------------+ | refcount | bytes | +-----------+----------------------------------------------------------+ refcount is a malloc_refcount bytes is an array of bytes of the requested length Both parts are placed in the same allocation returned from gpr_malloc */ malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); /* Initial refcount on rc is 1 - and it's up to the caller to release this reference. */ gpr_ref_init(&rc->refs, 1); rc->base.ref = malloc_ref; rc->base.unref = malloc_unref; /* Build up the slice to be returned. */ /* The slices refcount points back to the allocated block. */ slice.refcount = &rc->base; /* The data bytes are placed immediately after the refcount struct */ slice.data.refcounted.bytes = (gpr_uint8 *)(rc + 1); /* And the length of the block is set to the requested length */ slice.data.refcounted.length = length; } else { /* small slice: just inline the data */ slice.refcount = NULL; slice.data.inlined.length = (gpr_uint8)length; } return slice; } gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) { gpr_slice subset; GPR_ASSERT(end >= begin); if (source.refcount) { /* Enforce preconditions */ GPR_ASSERT(source.data.refcounted.length >= end); /* Build the result */ subset.refcount = source.refcount; /* Point into the source array */ subset.data.refcounted.bytes = source.data.refcounted.bytes + begin; subset.data.refcounted.length = end - begin; } else { /* Enforce preconditions */ GPR_ASSERT(source.data.inlined.length >= end); subset.refcount = NULL; subset.data.inlined.length = (gpr_uint8)(end - begin); memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin, end - begin); } return subset; } gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) { gpr_slice subset; if (end - begin <= sizeof(subset.data.inlined.bytes)) { subset.refcount = NULL; subset.data.inlined.length = (gpr_uint8)(end - begin); memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin, end - begin); } else { subset = gpr_slice_sub_no_ref(source, begin, end); /* Bump the refcount */ subset.refcount->ref(subset.refcount); } return subset; } gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) { gpr_slice tail; if (source->refcount == NULL) { /* inlined data, copy it out */ GPR_ASSERT(source->data.inlined.length >= split); tail.refcount = NULL; tail.data.inlined.length = (gpr_uint8)(source->data.inlined.length - split); memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split, tail.data.inlined.length); source->data.inlined.length = (gpr_uint8)split; } else { size_t tail_length = source->data.refcounted.length - split; GPR_ASSERT(source->data.refcounted.length >= split); if (tail_length < sizeof(tail.data.inlined.bytes)) { /* Copy out the bytes - it'll be cheaper than refcounting */ tail.refcount = NULL; tail.data.inlined.length = (gpr_uint8)tail_length; memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, tail_length); } else { /* Build the result */ tail.refcount = source->refcount; /* Bump the refcount */ tail.refcount->ref(tail.refcount); /* Point into the source array */ tail.data.refcounted.bytes = source->data.refcounted.bytes + split; tail.data.refcounted.length = tail_length; } source->data.refcounted.length = split; } return tail; } gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) { gpr_slice head; if (source->refcount == NULL) { GPR_ASSERT(source->data.inlined.length >= split); head.refcount = NULL; head.data.inlined.length = (gpr_uint8)split; memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split); source->data.inlined.length = (gpr_uint8)(source->data.inlined.length - split); memmove(source->data.inlined.bytes, source->data.inlined.bytes + split, source->data.inlined.length); } else if (split < sizeof(head.data.inlined.bytes)) { GPR_ASSERT(source->data.refcounted.length >= split); head.refcount = NULL; head.data.inlined.length = (gpr_uint8)split; memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split); source->data.refcounted.bytes += split; source->data.refcounted.length -= split; } else { GPR_ASSERT(source->data.refcounted.length >= split); /* Build the result */ head.refcount = source->refcount; /* Bump the refcount */ head.refcount->ref(head.refcount); /* Point into the source array */ head.data.refcounted.bytes = source->data.refcounted.bytes; head.data.refcounted.length = split; source->data.refcounted.bytes += split; source->data.refcounted.length -= split; } return head; } int gpr_slice_cmp(gpr_slice a, gpr_slice b) { int d = (int)(GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b)); if (d != 0) return d; return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b), GPR_SLICE_LENGTH(a)); } int gpr_slice_str_cmp(gpr_slice a, const char *b) { size_t b_length = strlen(b); int d = (int)(GPR_SLICE_LENGTH(a) - b_length); if (d != 0) return d; return memcmp(GPR_SLICE_START_PTR(a), b, b_length); } char *gpr_slice_to_cstring(gpr_slice slice) { char *result = gpr_malloc(GPR_SLICE_LENGTH(slice) + 1); memcpy(result, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)); result[GPR_SLICE_LENGTH(slice)] = '\0'; return result; } grpc-0.11.1/src/core/support/time_win32.c0000644000175000017500000000625512600663151020306 0ustar apollockapollock/* * * 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. * */ /* Win32 code for gpr time support. */ #include #ifdef GPR_WIN32 #include #include #include static LARGE_INTEGER g_start_time; static double g_time_scale; void gpr_time_init(void) { LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&g_start_time); g_time_scale = 1.0 / frequency.QuadPart; } gpr_timespec gpr_now(gpr_clock_type clock) { gpr_timespec now_tv; struct _timeb now_tb; LARGE_INTEGER timestamp; double now_dbl; now_tv.clock_type = clock; switch (clock) { case GPR_CLOCK_REALTIME: _ftime_s(&now_tb); now_tv.tv_sec = now_tb.time; now_tv.tv_nsec = now_tb.millitm * 1000000; break; case GPR_CLOCK_MONOTONIC: QueryPerformanceCounter(×tamp); now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale; now_tv.tv_sec = (time_t)now_dbl; now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9); break; case GPR_CLOCK_PRECISE: gpr_precise_clock_now(&now_tv); break; } return now_tv; } void gpr_sleep_until(gpr_timespec until) { gpr_timespec now; gpr_timespec delta; DWORD sleep_millis; for (;;) { /* We could simplify by using clock_nanosleep instead, but it might be * slightly less portable. */ now = gpr_now(until.clock_type); if (gpr_time_cmp(until, now) <= 0) { return; } delta = gpr_time_sub(until, now); sleep_millis = (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS; Sleep(sleep_millis); } } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/cmdline.c0000644000175000017500000002114412600663151017733 0ustar apollockapollock/* * * 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 #include #include #include #include "src/core/support/string.h" #include #include #include typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype; typedef struct arg { const char *name; const char *help; argtype type; void *value; struct arg *next; } arg; struct gpr_cmdline { const char *description; arg *args; const char *argv0; const char *extra_arg_name; const char *extra_arg_help; void (*extra_arg)(void *user_data, const char *arg); void *extra_arg_user_data; void (*state)(gpr_cmdline *cl, char *arg); arg *cur_arg; }; static void normal_state(gpr_cmdline *cl, char *arg); gpr_cmdline *gpr_cmdline_create(const char *description) { gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline)); memset(cl, 0, sizeof(gpr_cmdline)); cl->description = description; cl->state = normal_state; return cl; } void gpr_cmdline_destroy(gpr_cmdline *cl) { while (cl->args) { arg *a = cl->args; cl->args = a->next; gpr_free(a); } gpr_free(cl); } static void add_arg(gpr_cmdline *cl, const char *name, const char *help, argtype type, void *value) { arg *a; for (a = cl->args; a; a = a->next) { GPR_ASSERT(0 != strcmp(a->name, name)); } a = gpr_malloc(sizeof(arg)); memset(a, 0, sizeof(arg)); a->name = name; a->help = help; a->type = type; a->value = value; a->next = cl->args; cl->args = a; } void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help, int *value) { add_arg(cl, name, help, ARGTYPE_INT, value); } void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help, int *value) { add_arg(cl, name, help, ARGTYPE_BOOL, value); } void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help, char **value) { add_arg(cl, name, help, ARGTYPE_STRING, value); } void gpr_cmdline_on_extra_arg( gpr_cmdline *cl, const char *name, const char *help, void (*on_extra_arg)(void *user_data, const char *arg), void *user_data) { GPR_ASSERT(!cl->extra_arg); GPR_ASSERT(on_extra_arg); cl->extra_arg = on_extra_arg; cl->extra_arg_user_data = user_data; cl->extra_arg_name = name; cl->extra_arg_help = help; } /* recursively descend argument list, adding the last element to s first - so that arguments are added in the order they were added to the list by api calls */ static void add_args_to_usage(gpr_strvec *s, arg *a) { char *tmp; if (!a) return; add_args_to_usage(s, a->next); switch (a->type) { case ARGTYPE_BOOL: gpr_asprintf(&tmp, " [--%s|--no-%s]", a->name, a->name); gpr_strvec_add(s, tmp); break; case ARGTYPE_STRING: gpr_asprintf(&tmp, " [--%s=string]", a->name); gpr_strvec_add(s, tmp); break; case ARGTYPE_INT: gpr_asprintf(&tmp, " [--%s=int]", a->name); gpr_strvec_add(s, tmp); break; } } char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) { /* TODO(ctiller): make this prettier */ gpr_strvec s; char *tmp; const char *name = strrchr(argv0, '/'); if (name) { name++; } else { name = argv0; } gpr_strvec_init(&s); gpr_asprintf(&tmp, "Usage: %s", name); gpr_strvec_add(&s, tmp); add_args_to_usage(&s, cl->args); if (cl->extra_arg) { gpr_asprintf(&tmp, " [%s...]", cl->extra_arg_name); gpr_strvec_add(&s, tmp); } gpr_strvec_add(&s, gpr_strdup("\n")); tmp = gpr_strvec_flatten(&s, NULL); gpr_strvec_destroy(&s); return tmp; } static void print_usage_and_die(gpr_cmdline *cl) { char *usage = gpr_cmdline_usage_string(cl, cl->argv0); fprintf(stderr, "%s", usage); gpr_free(usage); exit(1); } static void extra_state(gpr_cmdline *cl, char *arg) { if (!cl->extra_arg) print_usage_and_die(cl); cl->extra_arg(cl->extra_arg_user_data, arg); } static arg *find_arg(gpr_cmdline *cl, char *name) { arg *a; for (a = cl->args; a; a = a->next) { if (0 == strcmp(a->name, name)) { break; } } if (!a) { fprintf(stderr, "Unknown argument: %s\n", name); print_usage_and_die(cl); } return a; } static void value_state(gpr_cmdline *cl, char *arg) { long intval; char *end; GPR_ASSERT(cl->cur_arg); switch (cl->cur_arg->type) { case ARGTYPE_INT: intval = strtol(arg, &end, 0); if (*end || intval < INT_MIN || intval > INT_MAX) { fprintf(stderr, "expected integer, got '%s' for %s\n", arg, cl->cur_arg->name); print_usage_and_die(cl); } *(int *)cl->cur_arg->value = (int)intval; break; case ARGTYPE_BOOL: if (0 == strcmp(arg, "1") || 0 == strcmp(arg, "true")) { *(int *)cl->cur_arg->value = 1; } else if (0 == strcmp(arg, "0") || 0 == strcmp(arg, "false")) { *(int *)cl->cur_arg->value = 0; } else { fprintf(stderr, "expected boolean, got '%s' for %s\n", arg, cl->cur_arg->name); print_usage_and_die(cl); } break; case ARGTYPE_STRING: *(char **)cl->cur_arg->value = arg; break; } cl->state = normal_state; } static void normal_state(gpr_cmdline *cl, char *arg) { char *eq = NULL; char *tmp = NULL; char *arg_name = NULL; if (0 == strcmp(arg, "-help") || 0 == strcmp(arg, "--help") || 0 == strcmp(arg, "-h")) { print_usage_and_die(cl); } cl->cur_arg = NULL; if (arg[0] == '-') { if (arg[1] == '-') { if (arg[2] == 0) { /* handle '--' to move to just extra args */ cl->state = extra_state; return; } arg += 2; } else { arg += 1; } /* first byte of arg is now past the leading '-' or '--' */ if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') { /* arg is of the form '--no-foo' - it's a flag disable */ arg += 3; cl->cur_arg = find_arg(cl, arg); if (cl->cur_arg->type != ARGTYPE_BOOL) { fprintf(stderr, "%s is not a flag argument\n", arg); print_usage_and_die(cl); } *(int *)cl->cur_arg->value = 0; return; /* early out */ } eq = strchr(arg, '='); if (eq != NULL) { /* copy the string into a temp buffer and extract the name */ tmp = arg_name = gpr_malloc((size_t)(eq - arg + 1)); memcpy(arg_name, arg, (size_t)(eq - arg)); arg_name[eq - arg] = 0; } else { arg_name = arg; } cl->cur_arg = find_arg(cl, arg_name); if (eq != NULL) { /* arg was of the type --foo=value, parse the value */ value_state(cl, eq + 1); } else if (cl->cur_arg->type != ARGTYPE_BOOL) { /* flag types don't have a '--foo value' variant, other types do */ cl->state = value_state; } else { /* flag parameter: just set the value */ *(int *)cl->cur_arg->value = 1; } } else { extra_state(cl, arg); } gpr_free(tmp); } void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) { int i; GPR_ASSERT(argc >= 1); cl->argv0 = argv[0]; for (i = 1; i < argc; i++) { cl->state(cl, argv[i]); } } grpc-0.11.1/src/core/support/log_win32.c0000644000175000017500000000774012600663151020131 0ustar apollockapollock/* * * 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 #ifdef GPR_WIN32 #include #include #include #include #include #include #include #include "src/core/support/string.h" #include "src/core/support/string_win32.h" void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format, ...) { char *message = NULL; va_list args; int ret; /* Determine the length. */ va_start(args, format); ret = _vscprintf(format, args); va_end(args); if (ret < 0) { message = NULL; } else { /* Allocate a new buffer, with space for the NUL terminator. */ size_t strp_buflen = (size_t)ret + 1; message = gpr_malloc(strp_buflen); /* Print to the buffer. */ va_start(args, format); ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args); va_end(args); if ((size_t)ret != strp_buflen - 1) { /* This should never happen. */ gpr_free(message); message = NULL; } } gpr_log_message(file, line, severity, message); gpr_free(message); } /* Simple starter implementation */ void gpr_default_log(gpr_log_func_args *args) { char *final_slash; const char *display_file; char time_buffer[64]; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); struct tm tm; final_slash = strrchr(args->file, '\\'); if (final_slash == NULL) display_file = args->file; else display_file = final_slash + 1; if (localtime_s(&tm, &now.tv_sec)) { strcpy(time_buffer, "error:localtime"); } else if (0 == strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { strcpy(time_buffer, "error:strftime"); } fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n", gpr_log_severity_string(args->severity), time_buffer, (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line, args->message); } char *gpr_format_message(DWORD messageid) { LPTSTR tmessage; char *message; DWORD status = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)(&tmessage), 0, NULL); if (status == 0) return gpr_strdup("Unable to retrieve error string"); message = gpr_tchar_to_char(tmessage); LocalFree(tmessage); return message; } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/murmur_hash.c0000644000175000017500000000556512600663151020663 0ustar apollockapollock/* * * 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/support/murmur_hash.h" #define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r))) #define FMIX32(h) \ (h) ^= (h) >> 16; \ (h) *= 0x85ebca6b; \ (h) ^= (h) >> 13; \ (h) *= 0xc2b2ae35; \ (h) ^= (h) >> 16; /* Block read - if your platform needs to do endian-swapping or can only handle aligned reads, do the conversion here */ #define GETBLOCK32(p, i) (p)[(i)] gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed) { const gpr_uint8 *data = (const gpr_uint8 *)key; const size_t nblocks = len / 4; int i; gpr_uint32 h1 = seed; gpr_uint32 k1; const gpr_uint32 c1 = 0xcc9e2d51; const gpr_uint32 c2 = 0x1b873593; const gpr_uint32 *blocks = ((const gpr_uint32 *)key) + nblocks; const gpr_uint8 *tail = (const gpr_uint8 *)(data + nblocks * 4); /* body */ for (i = -(int)nblocks; i; i++) { k1 = GETBLOCK32(blocks, i); k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; h1 = ROTL32(h1, 13); h1 = h1 * 5 + 0xe6546b64; } k1 = 0; /* tail */ switch (len & 3) { case 3: k1 ^= ((gpr_uint32)tail[2]) << 16; case 2: k1 ^= ((gpr_uint32)tail[1]) << 8; case 1: k1 ^= tail[0]; k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; }; /* finalization */ h1 ^= (gpr_uint32)len; FMIX32(h1); return h1; } grpc-0.11.1/src/core/support/time_precise.h0000644000175000017500000000631612600663151021001 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_CORE_SUPPORT_TIME_PRECISE_H_ #define GRPC_CORE_SUPPORT_TIME_PRECISE_H_ #include #include #include #ifdef GRPC_TIMERS_RDTSC #if defined(__i386__) static void gpr_get_cycle_counter(long long int *clk) { long long int ret; __asm__ volatile("rdtsc" : "=A"(ret)); *clk = ret; } // ---------------------------------------------------------------- #elif defined(__x86_64__) || defined(__amd64__) static void gpr_get_cycle_counter(long long int *clk) { unsigned long long low, high; __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); *clk = (high << 32) | low; } #endif static gpr_once precise_clock_init = GPR_ONCE_INIT; static long long cycles_per_second = 0; static void gpr_precise_clock_init() { time_t start = time(NULL); gpr_precise_clock start_cycle; gpr_precise_clock end_cycle; while (time(NULL) == start) ; gpr_get_cycle_counter(&start_cycle); while (time(NULL) == start + 1) ; gpr_get_cycle_counter(&end_cycle); cycles_per_second = end_cycle - start_cycle; } static double grpc_precise_clock_scaling_factor() { gpr_once_init(&precise_clock_init, grpc_precise_clock_init); return 1e6 / cycles_per_second; } static void gpr_precise_clock_now(gpr_timespec *clk) { long long int counter; gpr_get_cycle_counter(&counter); clk->clock = GPR_CLOCK_REALTIME; clk->tv_sec = counter / cycles_per_second; clk->tv_nsec = counter % cycles_per_second; } #else /* GRPC_TIMERS_RDTSC */ static void gpr_precise_clock_now(gpr_timespec *clk) { *clk = gpr_now(GPR_CLOCK_REALTIME); clk->clock_type = GPR_CLOCK_PRECISE; } #endif /* GRPC_TIMERS_RDTSC */ #endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_ */ grpc-0.11.1/src/core/support/string_win32.h0000644000175000017500000000366212600663151020662 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H #define GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H #include #ifdef GPR_WIN32 /* These allocate new strings using gpr_malloc to convert from and to utf-8. */ LPTSTR gpr_char_to_tchar(LPCSTR input); LPSTR gpr_tchar_to_char(LPCTSTR input); #endif /* GPR_WIN32 */ #endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H */ grpc-0.11.1/src/core/support/file.h0000644000175000017500000000470012600663151017243 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_FILE_H #define GRPC_INTERNAL_CORE_SUPPORT_FILE_H #include #include #ifdef __cplusplus extern "C" { #endif /* File utility functions */ /* Loads the content of a file into a slice. add_null_terminator will add a NULL terminator if non-zero. The success parameter, if not NULL, will be set to 1 in case of success and 0 in case of failure. */ gpr_slice gpr_load_file(const char *filename, int add_null_terminator, int *success); /* Creates a temporary file from a prefix. If tmp_filename is not NULL, *tmp_filename is assigned the name of the created file and it is the responsibility of the caller to gpr_free it unless an error occurs in which case it will be set to NULL. */ FILE *gpr_tmpfile(const char *prefix, char **tmp_filename); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_SUPPORT_FILE_H */ grpc-0.11.1/src/core/support/string_win32.c0000644000175000017500000000644412600663151020656 0ustar apollockapollock/* * * 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. * */ /* Posix code for gpr snprintf support. */ #include #ifdef GPR_WIN32 #include #include #include #include #include "src/core/support/string.h" int gpr_asprintf(char **strp, const char *format, ...) { va_list args; int ret; size_t strp_buflen; /* Determine the length. */ va_start(args, format); ret = _vscprintf(format, args); va_end(args); if (ret < 0) { *strp = NULL; return -1; } /* Allocate a new buffer, with space for the NUL terminator. */ strp_buflen = (size_t)ret + 1; if ((*strp = gpr_malloc(strp_buflen)) == NULL) { /* This shouldn't happen, because gpr_malloc() calls abort(). */ return -1; } /* Print to the buffer. */ va_start(args, format); ret = vsnprintf_s(*strp, strp_buflen, _TRUNCATE, format, args); va_end(args); if ((size_t)ret == strp_buflen - 1) { return ret; } /* This should never happen. */ gpr_free(*strp); *strp = NULL; return -1; } #if defined UNICODE || defined _UNICODE LPTSTR gpr_char_to_tchar(LPCSTR input) { LPTSTR ret; int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); if (needed == 0) return NULL; ret = gpr_malloc(needed * sizeof(TCHAR)); MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed); return ret; } LPSTR gpr_tchar_to_char(LPCTSTR input) { LPSTR ret; int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); if (needed == 0) return NULL; ret = gpr_malloc(needed); WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); return ret; } #else char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); } char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); } #endif #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/cpu_iphone.c0000644000175000017500000000431612600663151020453 0ustar apollockapollock/* * * 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 #ifdef GPR_CPU_IPHONE /* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */ unsigned gpr_cpu_num_cores(void) { return 1; } /* Most code that's using this is using it to shard across work queues. So unless profiling shows it's a problem or there appears a way to detect the currently running CPU core, let's have it shard the default way. Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range, and some code might be relying on it. */ unsigned gpr_cpu_current_cpu(void) { return 0; } #endif /* GPR_CPU_IPHONE */ grpc-0.11.1/src/core/support/murmur_hash.h0000644000175000017500000000356012600663151020661 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H #define GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H #include #include /* compute the hash of key (length len) */ gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed); #endif /* GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H */ grpc-0.11.1/src/core/support/time.c0000644000175000017500000002333312600663151017260 0ustar apollockapollock/* * * 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. * */ /* Generic implementation of time calls. */ #include #include #include #include #include int gpr_time_cmp(gpr_timespec a, gpr_timespec b) { int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); GPR_ASSERT(a.clock_type == b.clock_type); if (cmp == 0) { cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); } return cmp; } gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) { return gpr_time_cmp(a, b) < 0 ? a : b; } gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) { return gpr_time_cmp(a, b) > 0 ? a : b; } /* There's no standard TIME_T_MIN and TIME_T_MAX, so we construct them. The following assumes that signed types are two's-complement and that bytes are 8 bits. */ /* The top bit of integral type t. */ #define TOP_BIT_OF_TYPE(t) (((gpr_uintmax)1) << ((8 * sizeof(t)) - 1)) /* Return whether integral type t is signed. */ #define TYPE_IS_SIGNED(t) (((t)1) > (t) ~(t)0) /* The minimum and maximum value of integral type t. */ #define TYPE_MIN(t) ((t)(TYPE_IS_SIGNED(t) ? TOP_BIT_OF_TYPE(t) : 0)) #define TYPE_MAX(t) \ ((t)(TYPE_IS_SIGNED(t) ? (TOP_BIT_OF_TYPE(t) - 1) \ : ((TOP_BIT_OF_TYPE(t) - 1) << 1) + 1)) gpr_timespec gpr_time_0(gpr_clock_type type) { gpr_timespec out; out.tv_sec = 0; out.tv_nsec = 0; out.clock_type = type; return out; } gpr_timespec gpr_inf_future(gpr_clock_type type) { gpr_timespec out; out.tv_sec = TYPE_MAX(time_t); out.tv_nsec = 0; out.clock_type = type; return out; } gpr_timespec gpr_inf_past(gpr_clock_type type) { gpr_timespec out; out.tv_sec = TYPE_MIN(time_t); out.tv_nsec = 0; out.clock_type = type; return out; } /* TODO(ctiller): consider merging _nanos, _micros, _millis into a single function for maintainability. Similarly for _seconds, _minutes, and _hours */ gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) { gpr_timespec result; result.clock_type = type; if (ns == LONG_MAX) { result = gpr_inf_future(type); } else if (ns == LONG_MIN) { result = gpr_inf_past(type); } else if (ns >= 0) { result.tv_sec = ns / GPR_NS_PER_SEC; result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC); } else { /* Calculation carefully formulated to avoid any possible under/overflow. */ result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1; result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC); } return result; } gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) { gpr_timespec result; result.clock_type = type; if (us == LONG_MAX) { result = gpr_inf_future(type); } else if (us == LONG_MIN) { result = gpr_inf_past(type); } else if (us >= 0) { result.tv_sec = us / 1000000; result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000); } else { /* Calculation carefully formulated to avoid any possible under/overflow. */ result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1; result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000); } return result; } gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) { gpr_timespec result; result.clock_type = type; if (ms == LONG_MAX) { result = gpr_inf_future(type); } else if (ms == LONG_MIN) { result = gpr_inf_past(type); } else if (ms >= 0) { result.tv_sec = ms / 1000; result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000); } else { /* Calculation carefully formulated to avoid any possible under/overflow. */ result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1; result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000); } return result; } gpr_timespec gpr_time_from_seconds(long s, gpr_clock_type type) { gpr_timespec result; result.clock_type = type; if (s == LONG_MAX) { result = gpr_inf_future(type); } else if (s == LONG_MIN) { result = gpr_inf_past(type); } else { result.tv_sec = s; result.tv_nsec = 0; } return result; } gpr_timespec gpr_time_from_minutes(long m, gpr_clock_type type) { gpr_timespec result; result.clock_type = type; if (m >= LONG_MAX / 60) { result = gpr_inf_future(type); } else if (m <= LONG_MIN / 60) { result = gpr_inf_past(type); } else { result.tv_sec = m * 60; result.tv_nsec = 0; } return result; } gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) { gpr_timespec result; result.clock_type = type; if (h >= LONG_MAX / 3600) { result = gpr_inf_future(type); } else if (h <= LONG_MIN / 3600) { result = gpr_inf_past(type); } else { result.tv_sec = h * 3600; result.tv_nsec = 0; } return result; } gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) { gpr_timespec sum; int inc = 0; GPR_ASSERT(b.clock_type == GPR_TIMESPAN); sum.clock_type = a.clock_type; sum.tv_nsec = a.tv_nsec + b.tv_nsec; if (sum.tv_nsec >= GPR_NS_PER_SEC) { sum.tv_nsec -= GPR_NS_PER_SEC; inc++; } if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) { sum = a; } else if (b.tv_sec == TYPE_MAX(time_t) || (b.tv_sec >= 0 && a.tv_sec >= TYPE_MAX(time_t) - b.tv_sec)) { sum = gpr_inf_future(sum.clock_type); } else if (b.tv_sec == TYPE_MIN(time_t) || (b.tv_sec <= 0 && a.tv_sec <= TYPE_MIN(time_t) - b.tv_sec)) { sum = gpr_inf_past(sum.clock_type); } else { sum.tv_sec = a.tv_sec + b.tv_sec; if (inc != 0 && sum.tv_sec == TYPE_MAX(time_t) - 1) { sum = gpr_inf_future(sum.clock_type); } else { sum.tv_sec += inc; } } return sum; } gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) { gpr_timespec diff; int dec = 0; if (b.clock_type == GPR_TIMESPAN) { diff.clock_type = a.clock_type; } else { GPR_ASSERT(a.clock_type == b.clock_type); diff.clock_type = GPR_TIMESPAN; } diff.tv_nsec = a.tv_nsec - b.tv_nsec; if (diff.tv_nsec < 0) { diff.tv_nsec += GPR_NS_PER_SEC; dec++; } if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) { diff = a; } else if (b.tv_sec == TYPE_MIN(time_t) || (b.tv_sec <= 0 && a.tv_sec >= TYPE_MAX(time_t) + b.tv_sec)) { diff = gpr_inf_future(GPR_CLOCK_REALTIME); } else if (b.tv_sec == TYPE_MAX(time_t) || (b.tv_sec >= 0 && a.tv_sec <= TYPE_MIN(time_t) + b.tv_sec)) { diff = gpr_inf_past(GPR_CLOCK_REALTIME); } else { diff.tv_sec = a.tv_sec - b.tv_sec; if (dec != 0 && diff.tv_sec == TYPE_MIN(time_t) + 1) { diff = gpr_inf_past(GPR_CLOCK_REALTIME); } else { diff.tv_sec -= dec; } } return diff; } int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) { int cmp_ab; GPR_ASSERT(a.clock_type == b.clock_type); GPR_ASSERT(threshold.clock_type == GPR_TIMESPAN); cmp_ab = gpr_time_cmp(a, b); if (cmp_ab == 0) return 1; if (cmp_ab < 0) { return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0; } else { return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0; } } gpr_int32 gpr_time_to_millis(gpr_timespec t) { if (t.tv_sec >= 2147483) { if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) { return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS; } return 2147483647; } else if (t.tv_sec <= -2147483) { /* TODO(ctiller): correct handling here (it's so far in the past do we care?) */ return -2147483647; } else { return (gpr_int32)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS); } } double gpr_timespec_to_micros(gpr_timespec t) { return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3; } gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) { if (t.clock_type == clock_type) { return t; } if (t.tv_nsec == 0) { if (t.tv_sec == TYPE_MAX(time_t)) { t.clock_type = clock_type; return t; } if (t.tv_sec == TYPE_MIN(time_t)) { t.clock_type = clock_type; return t; } } if (clock_type == GPR_TIMESPAN) { return gpr_time_sub(t, gpr_now(t.clock_type)); } if (t.clock_type == GPR_TIMESPAN) { return gpr_time_add(gpr_now(clock_type), t); } return gpr_time_add(gpr_now(clock_type), gpr_time_sub(t, gpr_now(t.clock_type))); } grpc-0.11.1/src/core/support/subprocess_posix.c0000644000175000017500000000627212600663151021737 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SUBPROCESS #include #include #include #include #include #include #include #include #include #include #include #include struct gpr_subprocess { int pid; int joined; }; const char *gpr_subprocess_binary_extension() { return ""; } gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { gpr_subprocess *r; int pid; char **exec_args; pid = fork(); if (pid == -1) { return NULL; } else if (pid == 0) { exec_args = gpr_malloc(((size_t)argc + 1) * sizeof(char *)); memcpy(exec_args, argv, (size_t)argc * sizeof(char *)); exec_args[argc] = NULL; execv(exec_args[0], exec_args); /* if we reach here, an error has occurred */ gpr_log(GPR_ERROR, "execv '%s' failed: %s", exec_args[0], strerror(errno)); _exit(1); return NULL; } else { r = gpr_malloc(sizeof(gpr_subprocess)); memset(r, 0, sizeof(*r)); r->pid = pid; return r; } } void gpr_subprocess_destroy(gpr_subprocess *p) { if (!p->joined) { kill(p->pid, SIGKILL); gpr_subprocess_join(p); } gpr_free(p); } int gpr_subprocess_join(gpr_subprocess *p) { int status; retry: if (waitpid(p->pid, &status, 0) == -1) { if (errno == EINTR) { goto retry; } gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno)); return -1; } return status; } void gpr_subprocess_interrupt(gpr_subprocess *p) { if (!p->joined) { kill(p->pid, SIGINT); } } #endif /* GPR_POSIX_SUBPROCESS */ grpc-0.11.1/src/core/support/log_posix.c0000644000175000017500000000643312600663151020327 0ustar apollockapollock/* * * 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 #if defined(GPR_POSIX_LOG) #include #include #include #include #include #include #include #include #include static gpr_intptr gettid(void) { return (gpr_intptr)pthread_self(); } void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format, ...) { char buf[64]; char *allocated = NULL; char *message = NULL; int ret; va_list args; va_start(args, format); ret = vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (ret < 0) { message = NULL; } else if ((size_t)ret <= sizeof(buf) - 1) { message = buf; } else { message = allocated = gpr_malloc(ret + 1); va_start(args, format); vsnprintf(message, ret + 1, format, args); va_end(args); } gpr_log_message(file, line, severity, message); gpr_free(allocated); } void gpr_default_log(gpr_log_func_args *args) { char *final_slash; const char *display_file; char time_buffer[64]; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); struct tm tm; final_slash = strrchr(args->file, '/'); if (final_slash == NULL) display_file = args->file; else display_file = final_slash + 1; if (!localtime_r(&now.tv_sec, &tm)) { strcpy(time_buffer, "error:localtime"); } else if (0 == strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { strcpy(time_buffer, "error:strftime"); } fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n", gpr_log_severity_string(args->severity), time_buffer, (int)(now.tv_nsec), gettid(), display_file, args->line, args->message); } #endif /* defined(GPR_POSIX_LOG) */ grpc-0.11.1/src/core/support/thd.c0000644000175000017500000000445412600663151017104 0ustar apollockapollock/* * * 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. * */ /* Posix implementation for gpr threads. */ #include #include enum { GPR_THD_JOINABLE = 1 }; gpr_thd_options gpr_thd_options_default(void) { gpr_thd_options options; memset(&options, 0, sizeof(options)); return options; } void gpr_thd_options_set_detached(gpr_thd_options *options) { options->flags &= ~GPR_THD_JOINABLE; } void gpr_thd_options_set_joinable(gpr_thd_options *options) { options->flags |= GPR_THD_JOINABLE; } int gpr_thd_options_is_detached(const gpr_thd_options *options) { if (!options) return 1; return (options->flags & GPR_THD_JOINABLE) == 0; } int gpr_thd_options_is_joinable(const gpr_thd_options *options) { if (!options) return 0; return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE; } grpc-0.11.1/src/core/support/file_posix.c0000644000175000017500000000522612600663151020464 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_FILE #include "src/core/support/file.h" #include #include #include #include #include #include #include #include "src/core/support/string.h" FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) { FILE *result = NULL; char *template; int fd; if (tmp_filename != NULL) *tmp_filename = NULL; gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix); GPR_ASSERT(template != NULL); fd = mkstemp(template); if (fd == -1) { gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.", template, strerror(errno)); goto end; } result = fdopen(fd, "w+"); if (result == NULL) { gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).", template, fd, strerror(errno)); unlink(template); close(fd); goto end; } end: if (result != NULL && tmp_filename != NULL) { *tmp_filename = template; } else { gpr_free(template); } return result; } #endif /* GPR_POSIX_FILE */ grpc-0.11.1/src/core/support/cpu_windows.c0000644000175000017500000000351612600663151020664 0ustar apollockapollock/* * * 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 #ifdef GPR_WIN32 #include unsigned gpr_cpu_num_cores(void) { SYSTEM_INFO si; GetSystemInfo(&si); return si.dwNumberOfProcessors; } unsigned gpr_cpu_current_cpu(void) { return GetCurrentProcessorNumber(); } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/host_port.c0000644000175000017500000000706112600663151020343 0ustar apollockapollock/* * * 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 #include #include "src/core/support/string.h" #include #include #include int gpr_join_host_port(char **out, const char *host, int port) { if (host[0] != '[' && strchr(host, ':') != NULL) { /* IPv6 literals must be enclosed in brackets. */ return gpr_asprintf(out, "[%s]:%d", host, port); } else { /* Ordinary non-bracketed host:port. */ return gpr_asprintf(out, "%s:%d", host, port); } } int gpr_split_host_port(const char *name, char **host, char **port) { const char *host_start; size_t host_len; const char *port_start; *host = NULL; *port = NULL; if (name[0] == '[') { /* Parse a bracketed host, typically an IPv6 literal. */ const char *rbracket = strchr(name, ']'); if (rbracket == NULL) { /* Unmatched [ */ return 0; } if (rbracket[1] == '\0') { /* ] */ port_start = NULL; } else if (rbracket[1] == ':') { /* ]: */ port_start = rbracket + 2; } else { /* ] */ return 0; } host_start = name + 1; host_len = (size_t)(rbracket - host_start); if (memchr(host_start, ':', host_len) == NULL) { /* Require all bracketed hosts to contain a colon, because a hostname or IPv4 address should never use brackets. */ return 0; } } else { const char *colon = strchr(name, ':'); if (colon != NULL && strchr(colon + 1, ':') == NULL) { /* Exactly 1 colon. Split into host:port. */ host_start = name; host_len = (size_t)(colon - name); port_start = colon + 1; } else { /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ host_start = name; host_len = strlen(name); port_start = NULL; } } /* Allocate return values. */ *host = gpr_malloc(host_len + 1); memcpy(*host, host_start, host_len); (*host)[host_len] = '\0'; if (port_start != NULL) { *port = gpr_strdup(port_start); } return 1; } grpc-0.11.1/src/core/support/string.c0000644000175000017500000001715412600663151017634 0ustar apollockapollock/* * * 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/support/string.h" #include #include #include #include #include #include #include char *gpr_strdup(const char *src) { char *dst; size_t len; if (!src) { return NULL; } len = strlen(src) + 1; dst = gpr_malloc(len); memcpy(dst, src, len); return dst; } typedef struct { size_t capacity; size_t length; char *data; } dump_out; static dump_out dump_out_create(void) { dump_out r = {0, 0, NULL}; return r; } static void dump_out_append(dump_out *out, char c) { if (out->length == out->capacity) { out->capacity = GPR_MAX(8, 2 * out->capacity); out->data = gpr_realloc(out->data, out->capacity); } out->data[out->length++] = c; } static void hexdump(dump_out *out, const char *buf, size_t len) { static const char hex[16] = "0123456789abcdef"; const gpr_uint8 *const beg = (const gpr_uint8 *)buf; const gpr_uint8 *const end = beg + len; const gpr_uint8 *cur; for (cur = beg; cur != end; ++cur) { if (cur != beg) dump_out_append(out, ' '); dump_out_append(out, hex[*cur >> 4]); dump_out_append(out, hex[*cur & 0xf]); } } static void asciidump(dump_out *out, const char *buf, size_t len) { const gpr_uint8 *const beg = (const gpr_uint8 *)buf; const gpr_uint8 *const end = beg + len; const gpr_uint8 *cur; int out_was_empty = (out->length == 0); if (!out_was_empty) { dump_out_append(out, ' '); dump_out_append(out, '\''); } for (cur = beg; cur != end; ++cur) { dump_out_append(out, isprint(*cur) ? *(char *)cur : '.'); } if (!out_was_empty) { dump_out_append(out, '\''); } } char *gpr_dump(const char *buf, size_t len, gpr_uint32 flags) { dump_out out = dump_out_create(); if (flags & GPR_DUMP_HEX) { hexdump(&out, buf, len); } if (flags & GPR_DUMP_ASCII) { asciidump(&out, buf, len); } dump_out_append(&out, 0); return out.data; } char *gpr_dump_slice(gpr_slice s, gpr_uint32 flags) { return gpr_dump((const char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s), flags); } int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) { gpr_uint32 out = 0; gpr_uint32 new; size_t i; if (len == 0) return 0; /* must have some bytes */ for (i = 0; i < len; i++) { if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */ new = 10 * out + (gpr_uint32)(buf[i] - '0'); if (new < out) return 0; /* overflow */ out = new; } *result = out; return 1; } void gpr_reverse_bytes(char *str, int len) { char *p1, *p2; for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) { char temp = *p1; *p1 = *p2; *p2 = temp; } } int gpr_ltoa(long value, char *string) { int i = 0; int neg = value < 0; if (value == 0) { string[0] = '0'; string[1] = 0; return 1; } if (neg) value = -value; while (value) { string[i++] = (char)('0' + value % 10); value /= 10; } if (neg) string[i++] = '-'; gpr_reverse_bytes(string, i); string[i] = 0; return i; } char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) { return gpr_strjoin_sep(strs, nstrs, "", final_length); } char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, size_t *final_length) { const size_t sep_len = strlen(sep); size_t out_length = 0; size_t i; char *out; for (i = 0; i < nstrs; i++) { out_length += strlen(strs[i]); } out_length += 1; /* null terminator */ if (nstrs > 0) { out_length += sep_len * (nstrs - 1); /* separators */ } out = gpr_malloc(out_length); out_length = 0; for (i = 0; i < nstrs; i++) { const size_t slen = strlen(strs[i]); if (i != 0) { memcpy(out + out_length, sep, sep_len); out_length += sep_len; } memcpy(out + out_length, strs[i], slen); out_length += slen; } out[out_length] = 0; if (final_length != NULL) { *final_length = out_length; } return out; } /** Finds the initial (\a begin) and final (\a end) offsets of the next * substring from \a str + \a read_offset until the next \a sep or the end of \a * str. * * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */ static int slice_find_separator_offset(const gpr_slice str, const char *sep, const size_t read_offset, size_t *begin, size_t *end) { size_t i; const gpr_uint8 *str_ptr = GPR_SLICE_START_PTR(str) + read_offset; const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset; const size_t sep_len = strlen(sep); if (str_len < sep_len) { return 0; } for (i = 0; i <= str_len - sep_len; i++) { if (memcmp(str_ptr + i, sep, sep_len) == 0) { *begin = read_offset; *end = read_offset + i; return 1; } } return 0; } void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) { const size_t sep_len = strlen(sep); size_t begin, end; GPR_ASSERT(sep_len > 0); if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) { do { gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end)); } while (slice_find_separator_offset(str, sep, end + sep_len, &begin, &end) != 0); gpr_slice_buffer_add_indexed( dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str))); } else { /* no sep found, add whole input */ gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str)); } } void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); } void gpr_strvec_destroy(gpr_strvec *sv) { size_t i; for (i = 0; i < sv->count; i++) { gpr_free(sv->strs[i]); } gpr_free(sv->strs); } void gpr_strvec_add(gpr_strvec *sv, char *str) { if (sv->count == sv->capacity) { sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2); sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); } sv->strs[sv->count++] = str; } char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { return gpr_strjoin((const char **)sv->strs, sv->count, final_length); } grpc-0.11.1/src/core/support/file.c0000644000175000017500000000613612600663151017243 0ustar apollockapollock/* * * 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/support/file.h" #include #include #include #include #include #include "src/core/support/string.h" gpr_slice gpr_load_file(const char *filename, int add_null_terminator, int *success) { unsigned char *contents = NULL; size_t contents_size = 0; char *error_msg = NULL; gpr_slice result = gpr_empty_slice(); FILE *file = fopen(filename, "rb"); size_t bytes_read = 0; if (file == NULL) { gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename, strerror(errno)); GPR_ASSERT(error_msg != NULL); goto end; } fseek(file, 0, SEEK_END); /* Converting to size_t on the assumption that it will not fail */ contents_size = (size_t)ftell(file); fseek(file, 0, SEEK_SET); contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0)); bytes_read = fread(contents, 1, contents_size, file); if (bytes_read < contents_size) { GPR_ASSERT(ferror(file)); gpr_asprintf(&error_msg, "Error %s occured while reading file %s.", strerror(errno), filename); GPR_ASSERT(error_msg != NULL); goto end; } if (success != NULL) *success = 1; if (add_null_terminator) { contents[contents_size++] = 0; } result = gpr_slice_new(contents, contents_size, gpr_free); end: if (error_msg != NULL) { gpr_log(GPR_ERROR, "%s", error_msg); gpr_free(error_msg); if (success != NULL) *success = 0; } if (file != NULL) fclose(file); return result; } grpc-0.11.1/src/core/support/env_posix.c0000644000175000017500000000402312600663151020327 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_ENV #include "src/core/support/env.h" #include #include #include "src/core/support/string.h" #include char *gpr_getenv(const char *name) { char *result = getenv(name); return result == NULL ? result : gpr_strdup(result); } void gpr_setenv(const char *name, const char *value) { int res = setenv(name, value, 1); GPR_ASSERT(res == 0); } #endif /* GPR_POSIX_ENV */ grpc-0.11.1/src/core/support/env_linux.c0000644000175000017500000000414312600663151020327 0ustar apollockapollock/* * * 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. * */ /* for secure_getenv. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #ifdef GPR_LINUX_ENV #include "src/core/support/env.h" #include #include #include #include "src/core/support/string.h" char *gpr_getenv(const char *name) { char *result = secure_getenv(name); return result == NULL ? result : gpr_strdup(result); } void gpr_setenv(const char *name, const char *value) { int res = setenv(name, value, 1); GPR_ASSERT(res == 0); } #endif /* GPR_LINUX_ENV */ grpc-0.11.1/src/core/support/log.c0000644000175000017500000000452412600663151017104 0ustar apollockapollock/* * * 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 #include #include extern void gpr_default_log(gpr_log_func_args *args); static gpr_log_func g_log_func = gpr_default_log; const char *gpr_log_severity_string(gpr_log_severity severity) { switch (severity) { case GPR_LOG_SEVERITY_DEBUG: return "D"; case GPR_LOG_SEVERITY_INFO: return "I"; case GPR_LOG_SEVERITY_ERROR: return "E"; } return "UNKNOWN"; } void gpr_log_message(const char *file, int line, gpr_log_severity severity, const char *message) { gpr_log_func_args lfargs; memset(&lfargs, 0, sizeof(lfargs)); lfargs.file = file; lfargs.line = line; lfargs.severity = severity; lfargs.message = message; g_log_func(&lfargs); } void gpr_set_log_function(gpr_log_func f) { g_log_func = f; } grpc-0.11.1/src/core/support/tls_pthread.c0000644000175000017500000000350412600663151020631 0ustar apollockapollock/* * * 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 #ifdef GPR_PTHREAD_TLS #include gpr_intptr gpr_tls_set(struct gpr_pthread_thread_local *tls, gpr_intptr value) { GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value)); return value; } #endif /* GPR_PTHREAD_TLS */ grpc-0.11.1/src/core/support/stack_lockfree.h0000644000175000017500000000444612600663151021312 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H #define GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H typedef struct gpr_stack_lockfree gpr_stack_lockfree; /* This stack must specify the maximum number of entries to track. The current implementation only allows up to 65534 entries */ gpr_stack_lockfree* gpr_stack_lockfree_create(int entries); void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack); /* Pass in a valid entry number for the next stack entry */ /* Returns 1 if this is the first element on the stack, 0 otherwise */ int gpr_stack_lockfree_push(gpr_stack_lockfree*, int entry); /* Returns -1 on empty or the actual entry number */ int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack); #endif /* GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H */ grpc-0.11.1/src/core/support/cpu_linux.c0000644000175000017500000000476412600663151020337 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif /* _GNU_SOURCE */ #include #ifdef GPR_CPU_LINUX #include #include #include #include #include #include #include static int ncpus = 0; static void init_num_cpus() { /* This must be signed. sysconf returns -1 when the number cannot be determined */ ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); if (ncpus < 1) { gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); ncpus = 1; } } unsigned gpr_cpu_num_cores(void) { static gpr_once once = GPR_ONCE_INIT; gpr_once_init(&once, init_num_cpus); return (unsigned)ncpus; } unsigned gpr_cpu_current_cpu(void) { int cpu = sched_getcpu(); if (cpu < 0) { gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); return 0; } return (unsigned)cpu; } #endif /* GPR_CPU_LINUX */ grpc-0.11.1/src/core/support/log_android.c0000644000175000017500000000556212600663151020607 0ustar apollockapollock/* * * 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 #ifdef GPR_ANDROID #include #include #include #include #include #include static android_LogPriority severity_to_log_priority(gpr_log_severity severity) { switch (severity) { case GPR_LOG_SEVERITY_DEBUG: return ANDROID_LOG_DEBUG; case GPR_LOG_SEVERITY_INFO: return ANDROID_LOG_INFO; case GPR_LOG_SEVERITY_ERROR: return ANDROID_LOG_ERROR; } return ANDROID_LOG_DEFAULT; } void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format, ...) { char *message = NULL; va_list args; va_start(args, format); vasprintf(&message, format, args); va_end(args); gpr_log_message(file, line, severity, message); free(message); } void gpr_default_log(gpr_log_func_args *args) { char *final_slash; const char *display_file; char *output = NULL; final_slash = strrchr(args->file, '/'); if (final_slash == NULL) display_file = args->file; else display_file = final_slash + 1; asprintf(&output, "%s:%d] %s", display_file, args->line, args->message); __android_log_write(severity_to_log_priority(args->severity), "GRPC", output); /* allocated by asprintf => use free, not gpr_free */ free(output); } #endif /* GPR_ANDROID */ grpc-0.11.1/src/core/support/string.h0000644000175000017500000001016412600663151017633 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_STRING_H #define GRPC_INTERNAL_CORE_SUPPORT_STRING_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* String utility functions */ /* Flags for gpr_dump function. */ #define GPR_DUMP_HEX 0x00000001 #define GPR_DUMP_ASCII 0x00000002 /* Converts array buf, of length len, into a C string according to the flags. Result should be freed with gpr_free() */ char *gpr_dump(const char *buf, size_t len, gpr_uint32 flags); /* Calls gpr_dump on a slice. */ char *gpr_dump_slice(gpr_slice slice, gpr_uint32 flags); /* Parses an array of bytes into an integer (base 10). Returns 1 on success, 0 on failure. */ int gpr_parse_bytes_to_uint32(const char *data, size_t length, gpr_uint32 *result); /* Minimum buffer size for calling ltoa */ #define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long)) /* Convert a long to a string in base 10; returns the length of the output string (or 0 on failure). output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */ int gpr_ltoa(long value, char *output); /* Reverse a run of bytes */ void gpr_reverse_bytes(char *str, int len); /* Join a set of strings, returning the resulting string. Total combined length (excluding null terminator) is returned in total_length if it is non-null. */ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length); /* Join a set of strings using a separator, returning the resulting string. Total combined length (excluding null terminator) is returned in total_length if it is non-null. */ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, size_t *total_length); /** Split \a str by the separator \a sep. Results are stored in \a dst, which * should be a properly initialized instance. */ void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst); /* A vector of strings... for building up a final string one piece at a time */ typedef struct { char **strs; size_t count; size_t capacity; } gpr_strvec; /* Initialize/destroy */ void gpr_strvec_init(gpr_strvec *strs); void gpr_strvec_destroy(gpr_strvec *strs); /* Add a string to a strvec, takes ownership of the string */ void gpr_strvec_add(gpr_strvec *strs, char *add); /* Return a joined string with all added substrings, optionally setting total_length as per gpr_strjoin */ char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_H */ grpc-0.11.1/src/core/support/alloc.c0000644000175000017500000000435712600663151017421 0ustar apollockapollock/* * * 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 #include #include void *gpr_malloc(size_t size) { void *p = malloc(size); if (!p) { abort(); } return p; } void gpr_free(void *p) { free(p); } void *gpr_realloc(void *p, size_t size) { p = realloc(p, size); if (!p) { abort(); } return p; } void *gpr_malloc_aligned(size_t size, size_t alignment_log) { size_t alignment = ((size_t)1) << alignment_log; size_t extra = alignment - 1 + sizeof(void *); void *p = gpr_malloc(size + extra); void **ret = (void **)(((gpr_uintptr)p + extra) & ~(alignment - 1)); ret[-1] = p; return (void *)ret; } void gpr_free_aligned(void *ptr) { free(((void **)ptr)[-1]); } grpc-0.11.1/src/core/support/stack_lockfree.c0000644000175000017500000001407012600663151021277 0ustar apollockapollock/* * * 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/support/stack_lockfree.h" #include #include #include #include #include #include /* The lockfree node structure is a single architecture-level word that allows for an atomic CAS to set it up. */ struct lockfree_node_contents { /* next thing to look at. Actual index for head, next index otherwise */ gpr_uint16 index; #ifdef GPR_ARCH_64 gpr_uint16 pad; gpr_uint32 aba_ctr; #else #ifdef GPR_ARCH_32 gpr_uint16 aba_ctr; #else #error Unsupported bit width architecture #endif #endif }; /* Use a union to make sure that these are in the same bits as an atm word */ typedef union lockfree_node { gpr_atm atm; struct lockfree_node_contents contents; } lockfree_node; #define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */ #define INVALID_ENTRY_INDEX \ ((1 << 16) - 1) /* reserve this entry as invalid \ */ struct gpr_stack_lockfree { lockfree_node *entries; lockfree_node head; /* An atomic entry describing curr head */ #ifndef NDEBUG /* Bitmap of pushed entries to check for double-push or pop */ gpr_atm pushed[(INVALID_ENTRY_INDEX + 1) / (8 * sizeof(gpr_atm))]; #endif }; gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) { gpr_stack_lockfree *stack; stack = gpr_malloc(sizeof(*stack)); /* Since we only allocate 16 bits to represent an entry number, * make sure that we are within the desired range */ /* Reserve the highest entry number as a dummy */ GPR_ASSERT(entries < INVALID_ENTRY_INDEX); stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]), ENTRY_ALIGNMENT_BITS); /* Clear out all entries */ memset(stack->entries, 0, entries * sizeof(stack->entries[0])); memset(&stack->head, 0, sizeof(stack->head)); #ifndef NDEBUG memset(&stack->pushed, 0, sizeof(stack->pushed)); #endif GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents)); /* Point the head at reserved dummy entry */ stack->head.contents.index = INVALID_ENTRY_INDEX; return stack; } void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) { gpr_free_aligned(stack->entries); gpr_free(stack); } int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { lockfree_node head; lockfree_node newhead; lockfree_node curent; lockfree_node newent; /* First fill in the entry's index and aba ctr for new head */ newhead.contents.index = (gpr_uint16)entry; /* Also post-increment the aba_ctr */ curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm); newhead.contents.aba_ctr = ++curent.contents.aba_ctr; gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm); #ifndef NDEBUG /* Check for double push */ { int pushed_index = entry / (8 * sizeof(gpr_atm)); int pushed_bit = entry % (8 * sizeof(gpr_atm)); gpr_atm old_val; old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], (gpr_atm)(1UL << pushed_bit)); GPR_ASSERT((old_val & (1UL << pushed_bit)) == 0); } #endif do { /* Atomically get the existing head value for use */ head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); /* Point to it */ newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm); newent.contents.index = head.contents.index; gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm); } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm)); /* Use rel_cas above to make sure that entry index is set properly */ return head.contents.index == INVALID_ENTRY_INDEX; } int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { lockfree_node head; lockfree_node newhead; do { head.atm = gpr_atm_acq_load(&(stack->head.atm)); if (head.contents.index == INVALID_ENTRY_INDEX) { return -1; } newhead.atm = gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm)); } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm)); #ifndef NDEBUG /* Check for valid pop */ { int pushed_index = head.contents.index / (8 * sizeof(gpr_atm)); int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm)); gpr_atm old_val; old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], -(gpr_atm)(1UL << pushed_bit)); GPR_ASSERT((old_val & (1UL << pushed_bit)) != 0); } #endif return head.contents.index; } grpc-0.11.1/src/core/support/sync_posix.c0000644000175000017500000000645412600663151020525 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SYNC #include #include #include #include #include void gpr_mu_init(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); } void gpr_mu_destroy(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); } void gpr_mu_lock(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_lock(mu) == 0); } void gpr_mu_unlock(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_unlock(mu) == 0); } int gpr_mu_trylock(gpr_mu *mu) { int err = pthread_mutex_trylock(mu); GPR_ASSERT(err == 0 || err == EBUSY); return err == 0; } /*----------------------------------------*/ void gpr_cv_init(gpr_cv *cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); } void gpr_cv_destroy(gpr_cv *cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { int err = 0; if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) { err = pthread_cond_wait(cv, mu); } else { struct timespec abs_deadline_ts; abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME); abs_deadline_ts.tv_sec = abs_deadline.tv_sec; abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec; err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts); } GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); return err == ETIMEDOUT; } void gpr_cv_signal(gpr_cv *cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); } void gpr_cv_broadcast(gpr_cv *cv) { GPR_ASSERT(pthread_cond_broadcast(cv) == 0); } /*----------------------------------------*/ void gpr_once_init(gpr_once *once, void (*init_function)(void)) { GPR_ASSERT(pthread_once(once, init_function) == 0); } #endif /* GRP_POSIX_SYNC */ grpc-0.11.1/src/core/support/slice_buffer.c0000644000175000017500000001675212600663151020761 0ustar apollockapollock/* * * 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 #include #include #include #include /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */ #define GROW(x) (3 * (x) / 2) static void maybe_embiggen(gpr_slice_buffer *sb) { if (sb->count == sb->capacity) { sb->capacity = GROW(sb->capacity); GPR_ASSERT(sb->capacity > sb->count); if (sb->slices == sb->inlined) { sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice)); memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice)); } else { sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice)); } } } void gpr_slice_buffer_init(gpr_slice_buffer *sb) { sb->count = 0; sb->length = 0; sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS; sb->slices = sb->inlined; } void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) { gpr_slice_buffer_reset_and_unref(sb); if (sb->slices != sb->inlined) { gpr_free(sb->slices); } } gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, unsigned n) { gpr_slice *back; gpr_uint8 *out; sb->length += n; if (sb->count == 0) goto add_new; back = &sb->slices[sb->count - 1]; if (back->refcount) goto add_new; if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes)) goto add_new; out = back->data.inlined.bytes + back->data.inlined.length; back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + n); return out; add_new: maybe_embiggen(sb); back = &sb->slices[sb->count]; sb->count++; back->refcount = NULL; back->data.inlined.length = (gpr_uint8)n; return back->data.inlined.bytes; } size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) { size_t out = sb->count; maybe_embiggen(sb); sb->slices[out] = s; sb->length += GPR_SLICE_LENGTH(s); sb->count = out + 1; return out; } void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) { size_t n = sb->count; /* if both the last slice in the slice buffer and the slice being added are inlined (that is, that they carry their data inside the slice data structure), and the back slice is not full, then concatenate directly into the back slice, preventing many small slices being passed into writes */ if (!s.refcount && n) { gpr_slice *back = &sb->slices[n - 1]; if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) { if (s.data.inlined.length + back->data.inlined.length <= GPR_SLICE_INLINED_SIZE) { memcpy(back->data.inlined.bytes + back->data.inlined.length, s.data.inlined.bytes, s.data.inlined.length); back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + s.data.inlined.length); } else { size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length; memcpy(back->data.inlined.bytes + back->data.inlined.length, s.data.inlined.bytes, cp1); back->data.inlined.length = GPR_SLICE_INLINED_SIZE; maybe_embiggen(sb); back = &sb->slices[n]; sb->count = n + 1; back->refcount = NULL; back->data.inlined.length = (gpr_uint8)(s.data.inlined.length - cp1); memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1, s.data.inlined.length - cp1); } sb->length += s.data.inlined.length; return; /* early out */ } } gpr_slice_buffer_add_indexed(sb, s); } void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) { size_t i; for (i = 0; i < n; i++) { gpr_slice_buffer_add(sb, s[i]); } } void gpr_slice_buffer_pop(gpr_slice_buffer *sb) { if (sb->count != 0) { size_t count = --sb->count; sb->length -= GPR_SLICE_LENGTH(sb->slices[count]); } } void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) { size_t i; for (i = 0; i < sb->count; i++) { gpr_slice_unref(sb->slices[i]); } sb->count = 0; sb->length = 0; } void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) { GPR_SWAP(size_t, a->count, b->count); GPR_SWAP(size_t, a->capacity, b->capacity); GPR_SWAP(size_t, a->length, b->length); if (a->slices == a->inlined) { if (b->slices == b->inlined) { /* swap contents of inlined buffer */ gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS]; memcpy(temp, a->slices, b->count * sizeof(gpr_slice)); memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice)); memcpy(b->slices, temp, b->count * sizeof(gpr_slice)); } else { /* a is inlined, b is not - copy a inlined into b, fix pointers */ a->slices = b->slices; b->slices = b->inlined; memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice)); } } else if (b->slices == b->inlined) { /* b is inlined, a is not - copy b inlined int a, fix pointers */ b->slices = a->slices; a->slices = a->inlined; memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice)); } else { /* no inlining: easy swap */ GPR_SWAP(gpr_slice *, a->slices, b->slices); } } void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) { /* anything to move? */ if (src->count == 0) { return; } /* anything in dst? */ if (dst->count == 0) { gpr_slice_buffer_swap(src, dst); return; } /* both buffers have data - copy, and reset src */ gpr_slice_buffer_addn(dst, src->slices, src->count); src->count = 0; src->length = 0; } void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n) { GPR_ASSERT(n <= sb->length); sb->length -= n; for (;;) { size_t idx = sb->count - 1; gpr_slice slice = sb->slices[idx]; size_t slice_len = GPR_SLICE_LENGTH(slice); if (slice_len > n) { sb->slices[idx] = gpr_slice_sub_no_ref(slice, 0, slice_len - n); return; } else if (slice_len == n) { gpr_slice_unref(slice); sb->count = idx; return; } else { gpr_slice_unref(slice); n -= slice_len; sb->count = idx; } } } grpc-0.11.1/src/core/support/string_posix.c0000644000175000017500000000530312600663151021047 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_STRING #include #include #include #include int gpr_asprintf(char **strp, const char *format, ...) { va_list args; int ret; char buf[64]; size_t strp_buflen; /* Use a constant-sized buffer to determine the length. */ va_start(args, format); ret = vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (ret < 0) { *strp = NULL; return -1; } /* Allocate a new buffer, with space for the NUL terminator. */ strp_buflen = (size_t)ret + 1; if ((*strp = gpr_malloc(strp_buflen)) == NULL) { /* This shouldn't happen, because gpr_malloc() calls abort(). */ return -1; } /* Return early if we have all the bytes. */ if (strp_buflen <= sizeof(buf)) { memcpy(*strp, buf, strp_buflen); return ret; } /* Try again using the larger buffer. */ va_start(args, format); ret = vsnprintf(*strp, strp_buflen, format, args); va_end(args); if ((size_t)ret == strp_buflen - 1) { return ret; } /* This should never happen. */ gpr_free(*strp); *strp = NULL; return -1; } #endif /* GPR_POSIX_STRING */ grpc-0.11.1/src/core/support/thd_posix.c0000644000175000017500000000607112600663151020323 0ustar apollockapollock/* * * 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. * */ /* Posix implementation for gpr threads. */ #include #ifdef GPR_POSIX_SYNC #include #include #include #include #include #include #include struct thd_arg { void (*body)(void *arg); /* body of a thread */ void *arg; /* argument to a thread */ }; /* Body of every thread started via gpr_thd_new. */ static void *thread_body(void *v) { struct thd_arg a = *(struct thd_arg *)v; gpr_free(v); (*a.body)(a.arg); return NULL; } int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, const gpr_thd_options *options) { int thread_started; pthread_attr_t attr; pthread_t p; struct thd_arg *a = gpr_malloc(sizeof(*a)); a->body = thd_body; a->arg = arg; GPR_ASSERT(pthread_attr_init(&attr) == 0); if (gpr_thd_options_is_detached(options)) { GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); } else { GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); } thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0); GPR_ASSERT(pthread_attr_destroy(&attr) == 0); if (!thread_started) { gpr_free(a); } *t = (gpr_thd_id)p; return thread_started; } gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); } #endif /* GPR_POSIX_SYNC */ grpc-0.11.1/src/core/support/thd_win32.c0000644000175000017500000000724612600663151020130 0ustar apollockapollock/* * * 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. * */ /* Windows implementation for gpr threads. */ #include #ifdef GPR_WIN32 #include #include #include #include #if defined(_MSC_VER) #define thread_local __declspec(thread) #elif defined(__GNUC__) #define thread_local __thread #else #error "Unknown compiler - please file a bug report" #endif struct thd_info { void (*body)(void *arg); /* body of a thread */ void *arg; /* argument to a thread */ HANDLE join_event; /* if joinable, the join event */ int joinable; /* true if not detached */ }; static thread_local struct thd_info *g_thd_info; /* Destroys a thread info */ static void destroy_thread(struct thd_info *t) { if (t->joinable) CloseHandle(t->join_event); gpr_free(t); } /* Body of every thread started via gpr_thd_new. */ static DWORD WINAPI thread_body(void *v) { g_thd_info = (struct thd_info *)v; g_thd_info->body(g_thd_info->arg); if (g_thd_info->joinable) { BOOL ret = SetEvent(g_thd_info->join_event); GPR_ASSERT(ret); } else { destroy_thread(g_thd_info); } return 0; } int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, const gpr_thd_options *options) { HANDLE handle; struct thd_info *info = gpr_malloc(sizeof(*info)); info->body = thd_body; info->arg = arg; *t = 0; if (gpr_thd_options_is_joinable(options)) { info->joinable = 1; info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL); if (info->join_event == NULL) { gpr_free(info); return 0; } } else { info->joinable = 0; } handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL); if (handle == NULL) { destroy_thread(info); } else { *t = (gpr_thd_id)info; CloseHandle(handle); } return handle != NULL; } gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } void gpr_thd_join(gpr_thd_id t) { struct thd_info *info = (struct thd_info *)t; DWORD ret = WaitForSingleObject(info->join_event, INFINITE); GPR_ASSERT(ret == WAIT_OBJECT_0); destroy_thread(info); } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/file_win32.c0000644000175000017500000000546712600663151020273 0ustar apollockapollock/* * * 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 #ifdef GPR_WIN32 #include #include #include #include #include #include #include #include "src/core/support/file.h" #include "src/core/support/string_win32.h" FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) { FILE *result = NULL; LPTSTR template_string = NULL; TCHAR tmp_path[MAX_PATH]; TCHAR tmp_filename[MAX_PATH]; DWORD status; UINT success; if (tmp_filename_out != NULL) *tmp_filename_out = NULL; /* Convert our prefix to TCHAR. */ template_string = gpr_char_to_tchar(prefix); GPR_ASSERT(template_string); /* Get the path to the best temporary folder available. */ status = GetTempPath(MAX_PATH, tmp_path); if (status == 0 || status > MAX_PATH) goto end; /* Generate a unique filename with our template + temporary path. */ success = GetTempFileName(tmp_path, template_string, 0, tmp_filename); if (!success) goto end; /* Open a file there. */ if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end; end: if (result && tmp_filename_out) { *tmp_filename_out = gpr_tchar_to_char(tmp_filename); } gpr_free(template_string); return result; } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/sync.c0000644000175000017500000001000712600663151017270 0ustar apollockapollock/* * * 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. * */ /* Generic implementation of synchronization primitives. */ #include #include #include /* Number of mutexes to allocate for events, to avoid lock contention. Should be a prime. */ enum { event_sync_partitions = 31 }; /* Events are partitioned by address to avoid lock contention. */ static struct sync_array_s { gpr_mu mu; gpr_cv cv; } sync_array[event_sync_partitions]; /* This routine is executed once on first use, via event_once */ static gpr_once event_once = GPR_ONCE_INIT; static void event_initialize(void) { int i; for (i = 0; i != event_sync_partitions; i++) { gpr_mu_init(&sync_array[i].mu); gpr_cv_init(&sync_array[i].cv); } } /* Hash ev into an element of sync_array[]. */ static struct sync_array_s *hash(gpr_event *ev) { return &sync_array[((gpr_uintptr)ev) % event_sync_partitions]; } void gpr_event_init(gpr_event *ev) { gpr_once_init(&event_once, &event_initialize); ev->state = 0; } void gpr_event_set(gpr_event *ev, void *value) { struct sync_array_s *s = hash(ev); gpr_mu_lock(&s->mu); GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0); gpr_atm_rel_store(&ev->state, (gpr_atm)value); gpr_cv_broadcast(&s->cv); gpr_mu_unlock(&s->mu); GPR_ASSERT(value != NULL); } void *gpr_event_get(gpr_event *ev) { return (void *)gpr_atm_acq_load(&ev->state); } void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) { void *result = (void *)gpr_atm_acq_load(&ev->state); if (result == NULL) { struct sync_array_s *s = hash(ev); gpr_mu_lock(&s->mu); do { result = (void *)gpr_atm_acq_load(&ev->state); } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline)); gpr_mu_unlock(&s->mu); } return result; } void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); } void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); } void gpr_refn(gpr_refcount *r, int n) { gpr_atm_no_barrier_fetch_add(&r->count, n); } int gpr_unref(gpr_refcount *r) { gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1); GPR_ASSERT(prior > 0); return prior == 1; } void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n) { gpr_atm_rel_store(&c->value, n); } void gpr_stats_inc(gpr_stats_counter *c, gpr_intptr inc) { gpr_atm_no_barrier_fetch_add(&c->value, inc); } gpr_intptr gpr_stats_read(const gpr_stats_counter *c) { /* don't need acquire-load, but we have no no-barrier load yet */ return gpr_atm_acq_load(&c->value); } grpc-0.11.1/src/core/support/log_linux.c0000644000175000017500000000630312600663151020320 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _POSIX_SOURCE #define _POSIX_SOURCE #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #ifdef GPR_LINUX #include #include #include #include #include #include #include #include #include #include #include static long gettid(void) { return syscall(__NR_gettid); } void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format, ...) { char *message = NULL; va_list args; va_start(args, format); if (vasprintf(&message, format, args) == -1) { va_end(args); return; } va_end(args); gpr_log_message(file, line, severity, message); free(message); } void gpr_default_log(gpr_log_func_args *args) { char *final_slash; char *prefix; const char *display_file; char time_buffer[64]; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); struct tm tm; final_slash = strrchr(args->file, '/'); if (final_slash == NULL) display_file = args->file; else display_file = final_slash + 1; if (!localtime_r(&now.tv_sec, &tm)) { strcpy(time_buffer, "error:localtime"); } else if (0 == strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { strcpy(time_buffer, "error:strftime"); } gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]", gpr_log_severity_string(args->severity), time_buffer, (int)(now.tv_nsec), gettid(), display_file, args->line); fprintf(stderr, "%-60s %s\n", prefix, args->message); gpr_free(prefix); } #endif grpc-0.11.1/src/core/support/time_posix.c0000644000175000017500000001024612600663151020501 0ustar apollockapollock/* * * 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 #include #ifdef GPR_POSIX_TIME #include #include #include #include #include static struct timespec timespec_from_gpr(gpr_timespec gts) { struct timespec rv; rv.tv_sec = gts.tv_sec; rv.tv_nsec = gts.tv_nsec; return rv; } #if _POSIX_TIMERS > 0 static gpr_timespec gpr_from_timespec(struct timespec ts, gpr_clock_type clock) { gpr_timespec rv; rv.tv_sec = ts.tv_sec; rv.tv_nsec = (int)ts.tv_nsec; rv.clock_type = clock; return rv; } /** maps gpr_clock_type --> clockid_t for clock_gettime */ static clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, CLOCK_REALTIME}; void gpr_time_init(void) {} gpr_timespec gpr_now(gpr_clock_type clock) { struct timespec now; GPR_ASSERT(clock != GPR_TIMESPAN); if (clock == GPR_CLOCK_PRECISE) { gpr_timespec ret; gpr_precise_clock_now(&ret); return ret; } else { clock_gettime(clockid_for_gpr_clock[clock], &now); return gpr_from_timespec(now, clock); } } #else /* For some reason Apple's OSes haven't implemented clock_gettime. */ #include #include #include static double g_time_scale; static uint64_t g_time_start; void gpr_time_init(void) { mach_timebase_info_data_t tb = {0, 1}; mach_timebase_info(&tb); g_time_scale = tb.numer; g_time_scale /= tb.denom; g_time_start = mach_absolute_time(); } gpr_timespec gpr_now(gpr_clock_type clock) { gpr_timespec now; struct timeval now_tv; double now_dbl; now.clock_type = clock; switch (clock) { case GPR_CLOCK_REALTIME: gettimeofday(&now_tv, NULL); now.tv_sec = now_tv.tv_sec; now.tv_nsec = now_tv.tv_usec * 1000; break; case GPR_CLOCK_MONOTONIC: now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale; now.tv_sec = now_dbl * 1e-9; now.tv_nsec = now_dbl - now.tv_sec * 1e9; break; case GPR_CLOCK_PRECISE: gpr_precise_clock_now(&now); break; case GPR_TIMESPAN: abort(); } return now; } #endif void gpr_sleep_until(gpr_timespec until) { gpr_timespec now; gpr_timespec delta; struct timespec delta_ts; for (;;) { /* We could simplify by using clock_nanosleep instead, but it might be * slightly less portable. */ now = gpr_now(until.clock_type); if (gpr_time_cmp(until, now) <= 0) { return; } delta = gpr_time_sub(until, now); delta_ts = timespec_from_gpr(delta); if (nanosleep(&delta_ts, NULL) == 0) { break; } } } #endif /* GPR_POSIX_TIME */ grpc-0.11.1/src/core/support/env.h0000644000175000017500000000432712600663151017121 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_ENV_H #define GRPC_INTERNAL_CORE_SUPPORT_ENV_H #include #include #ifdef __cplusplus extern "C" { #endif /* Env utility functions */ /* Gets the environment variable value with the specified name. Returns a newly allocated string. It is the responsability of the caller to gpr_free the return value if not NULL (which means that the environment variable exists). */ char *gpr_getenv(const char *name); /* Sets the the environment with the specified name to the specified value. */ void gpr_setenv(const char *name, const char *value); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_SUPPORT_ENV_H */ grpc-0.11.1/src/core/support/sync_win32.c0000644000175000017500000001010112600663151020305 0ustar apollockapollock/* * * 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. * */ /* Win32 code for gpr synchronization support. */ #include #ifdef GPR_WIN32 #include #include #include void gpr_mu_init(gpr_mu *mu) { InitializeCriticalSection(&mu->cs); mu->locked = 0; } void gpr_mu_destroy(gpr_mu *mu) { DeleteCriticalSection(&mu->cs); } void gpr_mu_lock(gpr_mu *mu) { EnterCriticalSection(&mu->cs); GPR_ASSERT(!mu->locked); mu->locked = 1; } void gpr_mu_unlock(gpr_mu *mu) { mu->locked = 0; LeaveCriticalSection(&mu->cs); } int gpr_mu_trylock(gpr_mu *mu) { int result = TryEnterCriticalSection(&mu->cs); if (result) { if (mu->locked) { /* This thread already holds the lock. */ LeaveCriticalSection(&mu->cs); /* Decrement lock count. */ result = 0; /* Indicate failure */ } mu->locked = 1; } return result; } /*----------------------------------------*/ void gpr_cv_init(gpr_cv *cv) { InitializeConditionVariable(cv); } void gpr_cv_destroy(gpr_cv *cv) { /* Condition variables don't need destruction in Win32. */ } int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { int timeout = 0; DWORD timeout_max_ms; mu->locked = 0; if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) { SleepConditionVariableCS(cv, &mu->cs, INFINITE); } else { gpr_timespec now = gpr_now(abs_deadline.clock_type); gpr_int64 now_ms = (gpr_int64)now.tv_sec * 1000 + now.tv_nsec / 1000000; gpr_int64 deadline_ms = (gpr_int64)abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000; if (now_ms >= deadline_ms) { timeout = 1; } else { timeout_max_ms = (DWORD)min(deadline_ms - now_ms, INFINITE - 1); timeout = (SleepConditionVariableCS(cv, &mu->cs, timeout_max_ms) == 0 && GetLastError() == ERROR_TIMEOUT); } } mu->locked = 1; return timeout; } void gpr_cv_signal(gpr_cv *cv) { WakeConditionVariable(cv); } void gpr_cv_broadcast(gpr_cv *cv) { WakeAllConditionVariable(cv); } /*----------------------------------------*/ static void *dummy; struct run_once_func_arg { void (*init_function)(void); }; static BOOL CALLBACK run_once_func(gpr_once *once, void *v, void **pv) { struct run_once_func_arg *arg = v; (*arg->init_function)(); return 1; } void gpr_once_init(gpr_once *once, void (*init_function)(void)) { struct run_once_func_arg arg; arg.init_function = init_function; InitOnceExecuteOnce(once, run_once_func, &arg, &dummy); } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/support/cpu_posix.c0000644000175000017500000000522612600663151020334 0ustar apollockapollock/* * * 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 #ifdef GPR_CPU_POSIX #include #include #include #include #include static __thread char magic_thread_local; static int ncpus = 0; static void init_ncpus() { ncpus = sysconf(_SC_NPROCESSORS_ONLN); if (ncpus < 1) { gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); ncpus = 1; } } unsigned gpr_cpu_num_cores(void) { static gpr_once once = GPR_ONCE_INIT; gpr_once_init(&once, init_ncpus); return ncpus; } /* This is a cheap, but good enough, pointer hash for sharding things: */ static size_t shard_ptr(const void *info) { size_t x = (size_t)info; return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores(); } unsigned gpr_cpu_current_cpu(void) { /* NOTE: there's no way I know to return the actual cpu index portably... most code that's using this is using it to shard across work queues though, so here we use thread identity instead to achieve a similar though not identical effect */ return shard_ptr(&magic_thread_local); } #endif /* GPR_CPU_POSIX */ grpc-0.11.1/src/core/support/thd_internal.h0000644000175000017500000000341212600663151020776 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H #define GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H /* Internal interfaces between modules within the gpr support library. */ #endif /* GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H */ grpc-0.11.1/src/core/channel/0000755000175000017500000000000012600663151016046 5ustar apollockapollockgrpc-0.11.1/src/core/channel/noop_filter.h0000644000175000017500000000373312600663151020545 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H #define GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H #include "src/core/channel/channel_stack.h" /* No-op filter: simply takes everything it's given, and passes it on to the next filter. Exists simply as a starting point that others can take and customize for their own filters */ extern const grpc_channel_filter grpc_no_op_filter; #endif /* GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H */ grpc-0.11.1/src/core/channel/connected_channel.h0000644000175000017500000000436212600663151021656 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H #define GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H #include "src/core/channel/channel_stack.h" /* A channel filter representing a channel that is on a connected transport. This filter performs actual sending and receiving of messages. */ extern const grpc_channel_filter grpc_connected_channel_filter; /* Post construction fixup: set the transport in the connected channel. Must be called before any call stack using this filter is used. */ void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack, grpc_transport *transport); #endif /* GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H */ grpc-0.11.1/src/core/channel/channel_stack.c0000644000175000017500000001763312600663151021021 0ustar apollockapollock/* * * 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/channel/channel_stack.h" #include #include #include int grpc_trace_channel = 0; /* Memory layouts. Channel stack is laid out as: { grpc_channel_stack stk; padding to GPR_MAX_ALIGNMENT grpc_channel_element[stk.count]; per-filter memory, aligned to GPR_MAX_ALIGNMENT } Call stack is laid out as: { grpc_call_stack stk; padding to GPR_MAX_ALIGNMENT grpc_call_element[stk.count]; per-filter memory, aligned to GPR_MAX_ALIGNMENT } */ /* Given a size, round up to the next multiple of sizeof(void*) */ #define ROUND_UP_TO_ALIGNMENT_SIZE(x) \ (((x) + GPR_MAX_ALIGNMENT - 1) & ~(GPR_MAX_ALIGNMENT - 1)) size_t grpc_channel_stack_size(const grpc_channel_filter **filters, size_t filter_count) { /* always need the header, and size for the channel elements */ size_t size = ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) + ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element)); size_t i; GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 && "GPR_MAX_ALIGNMENT must be a power of two"); /* add the size for each filter */ for (i = 0; i < filter_count; i++) { size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data); } return size; } #define CHANNEL_ELEMS_FROM_STACK(stk) \ ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \ sizeof(grpc_channel_stack)))) #define CALL_ELEMS_FROM_STACK(stk) \ ((grpc_call_element *)((char *)(stk) + \ ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)))) grpc_channel_element *grpc_channel_stack_element( grpc_channel_stack *channel_stack, size_t index) { return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index; } grpc_channel_element *grpc_channel_stack_last_element( grpc_channel_stack *channel_stack) { return grpc_channel_stack_element(channel_stack, channel_stack->count - 1); } grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack, size_t index) { return CALL_ELEMS_FROM_STACK(call_stack) + index; } void grpc_channel_stack_init(const grpc_channel_filter **filters, size_t filter_count, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *metadata_context, grpc_channel_stack *stack) { size_t call_size = ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) + ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element)); grpc_channel_element *elems; char *user_data; size_t i; stack->count = filter_count; elems = CHANNEL_ELEMS_FROM_STACK(stack); user_data = ((char *)elems) + ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element)); /* init per-filter data */ for (i = 0; i < filter_count; i++) { elems[i].filter = filters[i]; elems[i].channel_data = user_data; elems[i].filter->init_channel_elem(&elems[i], master, args, metadata_context, i == 0, i == (filter_count - 1)); user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data); call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data); } GPR_ASSERT(user_data > (char *)stack); GPR_ASSERT((gpr_uintptr)(user_data - (char *)stack) == grpc_channel_stack_size(filters, filter_count)); stack->call_stack_size = call_size; } void grpc_channel_stack_destroy(grpc_channel_stack *stack) { grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack); size_t count = stack->count; size_t i; /* destroy per-filter data */ for (i = 0; i < count; i++) { channel_elems[i].filter->destroy_channel_elem(&channel_elems[i]); } } void grpc_call_stack_init(grpc_channel_stack *channel_stack, const void *transport_server_data, grpc_transport_stream_op *initial_op, grpc_call_stack *call_stack) { grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); size_t count = channel_stack->count; grpc_call_element *call_elems; char *user_data; size_t i; call_stack->count = count; call_elems = CALL_ELEMS_FROM_STACK(call_stack); user_data = ((char *)call_elems) + ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); /* init per-filter data */ for (i = 0; i < count; i++) { call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; call_elems[i].call_data = user_data; call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data, initial_op); user_data += ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); } } void grpc_call_stack_destroy(grpc_call_stack *stack) { grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack); size_t count = stack->count; size_t i; /* destroy per-filter data */ for (i = 0; i < count; i++) { elems[i].filter->destroy_call_elem(&elems[i]); } } void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op) { grpc_call_element *next_elem = elem + 1; next_elem->filter->start_transport_stream_op(next_elem, op); } char *grpc_call_next_get_peer(grpc_call_element *elem) { grpc_call_element *next_elem = elem + 1; return next_elem->filter->get_peer(next_elem); } void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op) { grpc_channel_element *next_elem = elem + 1; next_elem->filter->start_transport_op(next_elem, op); } grpc_channel_stack *grpc_channel_stack_from_top_element( grpc_channel_element *elem) { return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( sizeof(grpc_channel_stack))); } grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( sizeof(grpc_call_stack))); } void grpc_call_element_send_cancel(grpc_call_element *cur_elem) { grpc_transport_stream_op op; memset(&op, 0, sizeof(op)); op.cancel_with_status = GRPC_STATUS_CANCELLED; grpc_call_next_op(cur_elem, &op); } grpc-0.11.1/src/core/channel/channel_args.h0000644000175000017500000001003312600663151020640 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H #define GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H #include #include /* Copy some arguments */ grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src); /** Copy some arguments and add the to_add parameter in the end. If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */ grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, const grpc_arg *to_add, size_t num_to_add); /** Copy args from a then args from b into a new channel args */ grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, const grpc_channel_args *b); /** Destroy arguments created by grpc_channel_args_copy */ void grpc_channel_args_destroy(grpc_channel_args *a); /** Reads census_enabled settings from channel args. Returns 1 if census_enabled * is specified in channel args, otherwise returns 0. */ int grpc_channel_args_is_census_enabled(const grpc_channel_args *a); /** Returns the compression algorithm set in \a a. */ grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( const grpc_channel_args *a); /** Returns a channel arg instance with compression enabled. If \a a is * non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression * for the channel. */ grpc_channel_args *grpc_channel_args_set_compression_algorithm( grpc_channel_args *a, grpc_compression_algorithm algorithm); /** Sets the support for the given compression algorithm. By default, all * compression algorithms are enabled. It's an error to disable an algorithm set * by grpc_channel_args_set_compression_algorithm. * * Returns an instance will the updated algorithm states. The \a a pointer is * modified to point to the returned instance (which may be different from the * input value of \a a). */ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled); /** Returns the bitset representing the support state (true for enabled, false * for disabled) for compression algorithms. * * The i-th bit of the returned bitset corresponds to the i-th entry in the * grpc_compression_algorithm enum. */ int grpc_channel_args_compression_algorithm_get_states( const grpc_channel_args *a); #endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */ grpc-0.11.1/src/core/channel/client_channel.h0000644000175000017500000000610012600663151021162 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H #define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H #include "src/core/channel/channel_stack.h" #include "src/core/client_config/resolver.h" /* A client channel is a channel that begins disconnected, and can connect to some endpoint on demand. If that endpoint disconnects, it will be connected to again later. Calls on a disconnected client channel are queued until a connection is established. */ extern const grpc_channel_filter grpc_client_channel_filter; /* post-construction initializer to let the client channel know which transport setup it should cancel upon destruction, or initiate when it needs a connection */ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack, grpc_resolver *resolver); grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_channel_element *elem, int try_to_connect); void grpc_client_channel_watch_connectivity_state( grpc_channel_element *elem, grpc_connectivity_state *state, grpc_iomgr_closure *on_complete); grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set( grpc_channel_element *elem); void grpc_client_channel_add_interested_party(grpc_channel_element *channel, grpc_pollset *pollset); void grpc_client_channel_del_interested_party(grpc_channel_element *channel, grpc_pollset *pollset); #endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */ grpc-0.11.1/src/core/channel/context.h0000644000175000017500000000363312600663151017710 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H #define GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H /* Call object context pointers */ typedef enum { GRPC_CONTEXT_SECURITY = 0, GRPC_CONTEXT_TRACING, GRPC_CONTEXT_COUNT } grpc_context_index; typedef struct { void *value; void (*destroy)(void *); } grpc_call_context_element; #endif /* GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H */ grpc-0.11.1/src/core/channel/noop_filter.c0000644000175000017500000001174512600663151020542 0ustar apollockapollock/* * * 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/channel/noop_filter.h" #include typedef struct call_data { int unused; /* C89 requires at least one struct element */ } call_data; typedef struct channel_data { int unused; /* C89 requires at least one struct element */ } channel_data; /* used to silence 'variable not used' warnings */ static void ignore_unused(void *ignored) {} static void noop_mutate_op(grpc_call_element *elem, grpc_transport_stream_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; ignore_unused(calld); ignore_unused(channeld); /* do nothing */ } /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void noop_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { noop_mutate_op(elem, op); /* pass control down the stack */ grpc_call_next_op(elem, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; /* initialize members */ calld->unused = channeld->unused; if (initial_op) noop_mutate_op(elem, initial_op); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; ignore_unused(calld); ignore_unused(channeld); } /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; /* The first and the last filters tend to be implemented differently to handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!is_first); GPR_ASSERT(!is_last); /* initialize members */ channeld->unused = 0; } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; ignore_unused(channeld); } const grpc_channel_filter grpc_no_op_filter = {noop_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "no-op"}; grpc-0.11.1/src/core/channel/http_client_filter.c0000644000175000017500000002502312600663151022076 0ustar apollockapollock/* * 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/channel/http_client_filter.h" #include #include #include #include #include "src/core/support/string.h" typedef struct call_data { grpc_linked_mdelem method; grpc_linked_mdelem scheme; grpc_linked_mdelem authority; grpc_linked_mdelem te_trailers; grpc_linked_mdelem content_type; grpc_linked_mdelem user_agent; int sent_initial_metadata; int got_initial_metadata; grpc_stream_op_buffer *recv_ops; /** Closure to call when finished with the hc_on_recv hook */ grpc_iomgr_closure *on_done_recv; /** Receive closures are chained: we inject this closure as the on_done_recv up-call on transport_op, and remember to call our on_done_recv member after handling it. */ grpc_iomgr_closure hc_on_recv; } call_data; typedef struct channel_data { grpc_mdelem *te_trailers; grpc_mdelem *method; grpc_mdelem *scheme; grpc_mdelem *content_type; grpc_mdelem *status; /** complete user agent mdelem */ grpc_mdelem *user_agent; } channel_data; /* used to silence 'variable not used' warnings */ static void ignore_unused(void *ignored) {} static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; channel_data *channeld = elem->channel_data; if (md == channeld->status) { return NULL; } else if (md->key == channeld->status->key) { grpc_call_element_send_cancel(elem); return NULL; } else if (md->key == channeld->content_type->key) { return NULL; } return md; } static void hc_on_recv(void *user_data, int success) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; size_t i; size_t nops = calld->recv_ops->nops; grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; calld->got_initial_metadata = 1; grpc_metadata_batch_filter(&op->data.metadata, client_recv_filter, elem); } calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; channel_data *channeld = elem->channel_data; /* eat the things we'd like to set ourselves */ if (md->key == channeld->method->key) return NULL; if (md->key == channeld->scheme->key) return NULL; if (md->key == channeld->te_trailers->key) return NULL; if (md->key == channeld->content_type->key) return NULL; if (md->key == channeld->user_agent->key) return NULL; return md; } static void hc_mutate_op(grpc_call_element *elem, grpc_transport_stream_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; size_t i; if (op->send_ops && !calld->sent_initial_metadata) { size_t nops = op->send_ops->nops; grpc_stream_op *ops = op->send_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; calld->sent_initial_metadata = 1; grpc_metadata_batch_filter(&op->data.metadata, client_strip_filter, elem); /* Send : prefixed headers, which have to be before any application layer headers. */ grpc_metadata_batch_add_head(&op->data.metadata, &calld->method, GRPC_MDELEM_REF(channeld->method)); grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme, GRPC_MDELEM_REF(channeld->scheme)); grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers, GRPC_MDELEM_REF(channeld->te_trailers)); grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type, GRPC_MDELEM_REF(channeld->content_type)); grpc_metadata_batch_add_tail(&op->data.metadata, &calld->user_agent, GRPC_MDELEM_REF(channeld->user_agent)); break; } } if (op->recv_ops && !calld->got_initial_metadata) { /* substitute our callback for the higher callback */ calld->recv_ops = op->recv_ops; calld->on_done_recv = op->on_done_recv; op->on_done_recv = &calld->hc_on_recv; } } static void hc_start_transport_op(grpc_call_element *elem, grpc_transport_stream_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); hc_mutate_op(elem, op); grpc_call_next_op(elem, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { call_data *calld = elem->call_data; calld->sent_initial_metadata = 0; calld->got_initial_metadata = 0; calld->on_done_recv = NULL; grpc_iomgr_closure_init(&calld->hc_on_recv, hc_on_recv, elem); if (initial_op) hc_mutate_op(elem, initial_op); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; ignore_unused(calld); ignore_unused(channeld); } static const char *scheme_from_args(const grpc_channel_args *args) { unsigned i; if (args != NULL) { for (i = 0; i < args->num_args; ++i) { if (args->args[i].type == GRPC_ARG_STRING && strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) { return args->args[i].value.string; } } } return "http"; } static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx, const grpc_channel_args *args) { gpr_strvec v; size_t i; int is_first = 1; char *tmp; grpc_mdstr *result; gpr_strvec_init(&v); for (i = 0; args && i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", GRPC_ARG_PRIMARY_USER_AGENT_STRING); } else { if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); is_first = 0; gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); } } } gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ", grpc_version_string(), GPR_PLATFORM_STRING); is_first = 0; gpr_strvec_add(&v, tmp); for (i = 0; args && i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", GRPC_ARG_SECONDARY_USER_AGENT_STRING); } else { if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); is_first = 0; gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); } } } tmp = gpr_strvec_flatten(&v, NULL); gpr_strvec_destroy(&v); result = grpc_mdstr_from_string(mdctx, tmp, 0); gpr_free(tmp); return result; } /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *channel_args, grpc_mdctx *mdctx, int is_first, int is_last) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; /* The first and the last filters tend to be implemented differently to handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!is_last); /* initialize members */ channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers"); channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST"); channeld->scheme = grpc_mdelem_from_strings(mdctx, ":scheme", scheme_from_args(channel_args)); channeld->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200"); channeld->user_agent = grpc_mdelem_from_metadata_strings( mdctx, grpc_mdstr_from_string(mdctx, "user-agent", 0), user_agent_from_args(mdctx, channel_args)); } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; GRPC_MDELEM_UNREF(channeld->te_trailers); GRPC_MDELEM_UNREF(channeld->method); GRPC_MDELEM_UNREF(channeld->scheme); GRPC_MDELEM_UNREF(channeld->content_type); GRPC_MDELEM_UNREF(channeld->status); GRPC_MDELEM_UNREF(channeld->user_agent); } const grpc_channel_filter grpc_http_client_filter = { hc_start_transport_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "http-client"}; grpc-0.11.1/src/core/channel/compress_filter.c0000644000175000017500000003460012600663151021415 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include "src/core/channel/compress_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/compression/message_compress.h" #include "src/core/support/string.h" typedef struct call_data { gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */ grpc_linked_mdelem compression_algorithm_storage; grpc_linked_mdelem accept_encoding_storage; int remaining_slice_bytes; /**< Input data to be read, as per BEGIN_MESSAGE */ int written_initial_metadata; /**< Already processed initial md? */ /** Compression algorithm we'll try to use. It may be given by incoming * metadata, or by the channel's default compression settings. */ grpc_compression_algorithm compression_algorithm; /** If true, contents of \a compression_algorithm are authoritative */ int has_compression_algorithm; } call_data; typedef struct channel_data { /** Metadata key for the incoming (requested) compression algorithm */ grpc_mdstr *mdstr_request_compression_algorithm_key; /** Metadata key for the outgoing (used) compression algorithm */ grpc_mdstr *mdstr_outgoing_compression_algorithm_key; /** Metadata key for the accepted encodings */ grpc_mdstr *mdstr_compression_capabilities_key; /** Precomputed metadata elements for all available compression algorithms */ grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT]; /** Precomputed metadata elements for the accepted encodings */ grpc_mdelem *mdelem_accept_encoding; /** The default, channel-level, compression algorithm */ grpc_compression_algorithm default_compression_algorithm; } channel_data; /** Compress \a slices in place using \a algorithm. Returns 1 if compression did * actually happen, 0 otherwise (for example if the compressed output size was * larger than the raw input). * * Returns 1 if the data was actually compress and 0 otherwise. */ static int compress_send_sb(grpc_compression_algorithm algorithm, gpr_slice_buffer *slices) { int did_compress; gpr_slice_buffer tmp; gpr_slice_buffer_init(&tmp); did_compress = grpc_msg_compress(algorithm, slices, &tmp); if (did_compress) { gpr_slice_buffer_swap(slices, &tmp); } gpr_slice_buffer_destroy(&tmp); return did_compress; } /** For each \a md element from the incoming metadata, filter out the entry for * "grpc-encoding", using its value to populate the call data's * compression_algorithm field. */ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; if (md->key == channeld->mdstr_request_compression_algorithm_key) { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &calld->compression_algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.", md_c_str); calld->compression_algorithm = GRPC_COMPRESS_NONE; } calld->has_compression_algorithm = 1; return NULL; } return md; } static int skip_compression(channel_data *channeld, call_data *calld) { if (calld->has_compression_algorithm) { if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { return 1; } return 0; /* we have an actual call-specific algorithm */ } /* no per-call compression override */ return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE; } /** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying * the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length, * flags indicating compression is in effect) and replaces \a send_ops with it. * */ static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops, grpc_call_element *elem) { size_t i; call_data *calld = elem->call_data; int new_slices_added = 0; /* GPR_FALSE */ grpc_metadata_batch metadata; grpc_stream_op_buffer new_send_ops; grpc_sopb_init(&new_send_ops); for (i = 0; i < send_ops->nops; i++) { grpc_stream_op *sop = &send_ops->ops[i]; switch (sop->type) { case GRPC_OP_BEGIN_MESSAGE: grpc_sopb_add_begin_message( &new_send_ops, calld->slices.length, sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS); break; case GRPC_OP_SLICE: /* Once we reach the slices section of the original buffer, simply add * all the new (compressed) slices. We obviously want to do this only * once, hence the "new_slices_added" guard. */ if (!new_slices_added) { size_t j; for (j = 0; j < calld->slices.count; ++j) { grpc_sopb_add_slice(&new_send_ops, gpr_slice_ref(calld->slices.slices[j])); } new_slices_added = 1; /* GPR_TRUE */ } break; case GRPC_OP_METADATA: /* move the metadata to the new buffer. */ grpc_metadata_batch_move(&metadata, &sop->data.metadata); grpc_sopb_add_metadata(&new_send_ops, metadata); break; case GRPC_NO_OP: break; } } grpc_sopb_swap(send_ops, &new_send_ops); grpc_sopb_destroy(&new_send_ops); } /** Filter's "main" function, called for any incoming grpc_transport_stream_op * instance that holds a non-zero number of send operations, accesible to this * function in \a send_ops. */ static void process_send_ops(grpc_call_element *elem, grpc_stream_op_buffer *send_ops) { call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; size_t i; int did_compress = 0; /* In streaming calls, we need to reset the previously accumulated slices */ gpr_slice_buffer_reset_and_unref(&calld->slices); for (i = 0; i < send_ops->nops; ++i) { grpc_stream_op *sop = &send_ops->ops[i]; switch (sop->type) { case GRPC_OP_BEGIN_MESSAGE: /* buffer up slices until we've processed all the expected ones (as * given by GRPC_OP_BEGIN_MESSAGE) */ calld->remaining_slice_bytes = sop->data.begin_message.length; if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) { calld->has_compression_algorithm = 1; /* GPR_TRUE */ calld->compression_algorithm = GRPC_COMPRESS_NONE; } break; case GRPC_OP_METADATA: if (!calld->written_initial_metadata) { /* Parse incoming request for compression. If any, it'll be available * at calld->compression_algorithm */ grpc_metadata_batch_filter(&(sop->data.metadata), compression_md_filter, elem); if (!calld->has_compression_algorithm) { /* If no algorithm was found in the metadata and we aren't * exceptionally skipping compression, fall back to the channel * default */ calld->compression_algorithm = channeld->default_compression_algorithm; calld->has_compression_algorithm = 1; /* GPR_TRUE */ } /* hint compression algorithm */ grpc_metadata_batch_add_tail( &(sop->data.metadata), &calld->compression_algorithm_storage, GRPC_MDELEM_REF(channeld->mdelem_compression_algorithms [calld->compression_algorithm])); /* convey supported compression algorithms */ grpc_metadata_batch_add_tail( &(sop->data.metadata), &calld->accept_encoding_storage, GRPC_MDELEM_REF(channeld->mdelem_accept_encoding)); calld->written_initial_metadata = 1; /* GPR_TRUE */ } break; case GRPC_OP_SLICE: if (skip_compression(channeld, calld)) continue; GPR_ASSERT(calld->remaining_slice_bytes > 0); /* Increase input ref count, gpr_slice_buffer_add takes ownership. */ gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice)); calld->remaining_slice_bytes -= GPR_SLICE_LENGTH(sop->data.slice); if (calld->remaining_slice_bytes == 0) { did_compress = compress_send_sb(calld->compression_algorithm, &calld->slices); } break; case GRPC_NO_OP: break; } } /* Modify the send_ops stream_op_buffer depending on whether compression was * carried out */ if (did_compress) { finish_compressed_sopb(send_ops, elem); } } /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void compress_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { if (op->send_ops && op->send_ops->nops > 0) { process_send_ops(elem, op->send_ops); } /* pass control down the stack */ grpc_call_next_op(elem, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; /* initialize members */ gpr_slice_buffer_init(&calld->slices); calld->has_compression_algorithm = 0; calld->written_initial_metadata = 0; /* GPR_FALSE */ if (initial_op) { if (initial_op->send_ops && initial_op->send_ops->nops > 0) { process_send_ops(elem, initial_op->send_ops); } } } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; gpr_slice_buffer_destroy(&calld->slices); } /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { channel_data *channeld = elem->channel_data; grpc_compression_algorithm algo_idx; const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1]; char *accept_encoding_str; size_t accept_encoding_str_len; channeld->default_compression_algorithm = grpc_channel_args_get_compression_algorithm(args); channeld->mdstr_request_compression_algorithm_key = grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0); channeld->mdstr_outgoing_compression_algorithm_key = grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); channeld->mdstr_compression_capabilities_key = grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0); for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { char *algorithm_name; GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0); channeld->mdelem_compression_algorithms[algo_idx] = grpc_mdelem_from_metadata_strings( mdctx, GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key), grpc_mdstr_from_string(mdctx, algorithm_name, 0)); if (algo_idx > 0) { supported_algorithms_names[algo_idx - 1] = algorithm_name; } } /* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated * arrays, as to avoid the heap allocs */ accept_encoding_str = gpr_strjoin_sep( supported_algorithms_names, GPR_ARRAY_SIZE(supported_algorithms_names), ", ", &accept_encoding_str_len); channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings( mdctx, GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key), grpc_mdstr_from_string(mdctx, accept_encoding_str, 0)); gpr_free(accept_encoding_str); GPR_ASSERT(!is_last); } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *channeld = elem->channel_data; grpc_compression_algorithm algo_idx; GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key); GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key); GRPC_MDSTR_UNREF(channeld->mdstr_compression_capabilities_key); for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]); } GRPC_MDELEM_UNREF(channeld->mdelem_accept_encoding); } const grpc_channel_filter grpc_compress_filter = { compress_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "compress"}; grpc-0.11.1/src/core/channel/channel_args.c0000644000175000017500000001535512600663151020647 0ustar apollockapollock/* * * 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 #include "src/core/channel/channel_args.h" #include "src/core/support/string.h" #include #include #include #include static grpc_arg copy_arg(const grpc_arg *src) { grpc_arg dst; dst.type = src->type; dst.key = gpr_strdup(src->key); switch (dst.type) { case GRPC_ARG_STRING: dst.value.string = gpr_strdup(src->value.string); break; case GRPC_ARG_INTEGER: dst.value.integer = src->value.integer; break; case GRPC_ARG_POINTER: dst.value.pointer = src->value.pointer; dst.value.pointer.p = src->value.pointer.copy ? src->value.pointer.copy(src->value.pointer.p) : src->value.pointer.p; break; } return dst; } grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, const grpc_arg *to_add, size_t num_to_add) { grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args)); size_t i; size_t src_num_args = (src == NULL) ? 0 : src->num_args; if (!src && !to_add) { dst->num_args = 0; dst->args = NULL; return dst; } dst->num_args = src_num_args + num_to_add; dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args); for (i = 0; i < src_num_args; i++) { dst->args[i] = copy_arg(&src->args[i]); } for (i = 0; i < num_to_add; i++) { dst->args[i + src_num_args] = copy_arg(&to_add[i]); } return dst; } grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) { return grpc_channel_args_copy_and_add(src, NULL, 0); } grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, const grpc_channel_args *b) { return grpc_channel_args_copy_and_add(a, b->args, b->num_args); } void grpc_channel_args_destroy(grpc_channel_args *a) { size_t i; for (i = 0; i < a->num_args; i++) { switch (a->args[i].type) { case GRPC_ARG_STRING: gpr_free(a->args[i].value.string); break; case GRPC_ARG_INTEGER: break; case GRPC_ARG_POINTER: if (a->args[i].value.pointer.destroy) { a->args[i].value.pointer.destroy(a->args[i].value.pointer.p); } break; } gpr_free(a->args[i].key); } gpr_free(a->args); gpr_free(a); } int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) { size_t i; if (a == NULL) return 0; for (i = 0; i < a->num_args; i++) { if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) { return a->args[i].value.integer != 0; } } return 0; } grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( const grpc_channel_args *a) { size_t i; if (a == NULL) return 0; for (i = 0; i < a->num_args; ++i) { if (a->args[i].type == GRPC_ARG_INTEGER && !strcmp(GRPC_COMPRESSION_ALGORITHM_ARG, a->args[i].key)) { return a->args[i].value.integer; break; } } return GRPC_COMPRESS_NONE; } grpc_channel_args *grpc_channel_args_set_compression_algorithm( grpc_channel_args *a, grpc_compression_algorithm algorithm) { grpc_arg tmp; tmp.type = GRPC_ARG_INTEGER; tmp.key = GRPC_COMPRESSION_ALGORITHM_ARG; tmp.value.integer = algorithm; return grpc_channel_args_copy_and_add(a, &tmp, 1); } /** Returns 1 if the argument for compression algorithm's enabled states bitset * was found in \a a, returning the arg's value in \a states. Otherwise, returns * 0. */ static int find_compression_algorithm_states_bitset( const grpc_channel_args *a, int **states_arg) { if (a != NULL) { size_t i; for (i = 0; i < a->num_args; ++i) { if (a->args[i].type == GRPC_ARG_INTEGER && !strcmp(GRPC_COMPRESSION_ALGORITHM_STATE_ARG, a->args[i].key)) { *states_arg = &a->args[i].value.integer; return 1; /* GPR_TRUE */ } } } return 0; /* GPR_FALSE */ } grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) { int *states_arg; grpc_channel_args *result = *a; const int states_arg_found = find_compression_algorithm_states_bitset(*a, &states_arg); if (states_arg_found) { if (state != 0) { GPR_BITSET(states_arg, algorithm); } else { GPR_BITCLEAR(states_arg, algorithm); } } else { /* create a new arg */ grpc_arg tmp; tmp.type = GRPC_ARG_INTEGER; tmp.key = GRPC_COMPRESSION_ALGORITHM_STATE_ARG; /* all enabled by default */ tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; if (state != 0) { GPR_BITSET(&tmp.value.integer, algorithm); } else { GPR_BITCLEAR(&tmp.value.integer, algorithm); } result = grpc_channel_args_copy_and_add(*a, &tmp, 1); grpc_channel_args_destroy(*a); *a = result; } return result; } int grpc_channel_args_compression_algorithm_get_states( const grpc_channel_args *a) { int *states_arg; if (find_compression_algorithm_states_bitset(a, &states_arg)) { return *states_arg; } else { return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */ } } grpc-0.11.1/src/core/channel/http_client_filter.h0000644000175000017500000000365412600663151022111 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H #define GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H #include "src/core/channel/channel_stack.h" /* Processes metadata on the client side for HTTP2 transports */ extern const grpc_channel_filter grpc_http_client_filter; #define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" #endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */ grpc-0.11.1/src/core/channel/client_channel.c0000644000175000017500000006541212600663151021170 0ustar apollockapollock/* * * 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/channel/client_channel.h" #include #include #include "src/core/channel/channel_args.h" #include "src/core/channel/connected_channel.h" #include "src/core/surface/channel.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/string.h" #include "src/core/transport/connectivity_state.h" #include #include #include #include /* Client channel implementation */ typedef struct call_data call_data; typedef struct { /** metadata context for this channel */ grpc_mdctx *mdctx; /** resolver for this channel */ grpc_resolver *resolver; /** have we started resolving this channel */ int started_resolving; /** master channel - the grpc_channel instance that ultimately owns this channel_data via its channel stack. We occasionally use this to bump the refcount on the master channel to keep ourselves alive through an asynchronous operation. */ grpc_channel *master; /** mutex protecting client configuration, including all variables below in this data structure */ gpr_mu mu_config; /** currently active load balancer - guarded by mu_config */ grpc_lb_policy *lb_policy; /** incoming configuration - set by resolver.next guarded by mu_config */ grpc_client_config *incoming_configuration; /** a list of closures that are all waiting for config to come in */ grpc_iomgr_closure *waiting_for_config_closures; /** resolver callback */ grpc_iomgr_closure on_config_changed; /** connectivity state being tracked */ grpc_connectivity_state_tracker state_tracker; /** when an lb_policy arrives, should we try to exit idle */ int exit_idle_when_lb_policy_arrives; /** pollset_set of interested parties in a new connection */ grpc_pollset_set pollset_set; } channel_data; /** We create one watcher for each new lb_policy that is returned from a resolver, to watch for state changes from the lb_policy. When a state change is seen, we update the channel, and create a new watcher */ typedef struct { channel_data *chand; grpc_iomgr_closure on_changed; grpc_connectivity_state state; grpc_lb_policy *lb_policy; } lb_policy_connectivity_watcher; typedef enum { CALL_CREATED, CALL_WAITING_FOR_SEND, CALL_WAITING_FOR_CONFIG, CALL_WAITING_FOR_PICK, CALL_WAITING_FOR_CALL, CALL_ACTIVE, CALL_CANCELLED } call_state; struct call_data { /* owning element */ grpc_call_element *elem; gpr_mu mu_state; call_state state; gpr_timespec deadline; grpc_subchannel *picked_channel; grpc_iomgr_closure async_setup_task; grpc_transport_stream_op waiting_op; /* our child call stack */ grpc_subchannel_call *subchannel_call; grpc_linked_mdelem status; grpc_linked_mdelem details; }; static grpc_iomgr_closure *merge_into_waiting_op( grpc_call_element *elem, grpc_transport_stream_op *new_op) GRPC_MUST_USE_RESULT; static void handle_op_after_cancellation(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; if (op->send_ops) { grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops); op->on_done_send->cb(op->on_done_send->cb_arg, 0); } if (op->recv_ops) { char status[GPR_LTOA_MIN_BUFSIZE]; grpc_metadata_batch mdb; gpr_ltoa(GRPC_STATUS_CANCELLED, status); calld->status.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-status", status); calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message", "Cancelled"); calld->status.prev = calld->details.next = NULL; calld->status.next = &calld->details; calld->details.prev = &calld->status; mdb.list.head = &calld->status; mdb.list.tail = &calld->details; mdb.garbage.head = mdb.garbage.tail = NULL; mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME); grpc_sopb_add_metadata(op->recv_ops, mdb); *op->recv_state = GRPC_STREAM_CLOSED; op->on_done_recv->cb(op->on_done_recv->cb_arg, 1); } if (op->on_consumed) { op->on_consumed->cb(op->on_consumed->cb_arg, 0); } } typedef struct { grpc_iomgr_closure closure; grpc_call_element *elem; } waiting_call; static void perform_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op, int continuation); static void continue_with_pick(void *arg, int iomgr_success) { waiting_call *wc = arg; call_data *calld = wc->elem->call_data; perform_transport_stream_op(wc->elem, &calld->waiting_op, 1); gpr_free(wc); } static void add_to_lb_policy_wait_queue_locked_state_config( grpc_call_element *elem) { channel_data *chand = elem->channel_data; waiting_call *wc = gpr_malloc(sizeof(*wc)); grpc_iomgr_closure_init(&wc->closure, continue_with_pick, wc); wc->elem = elem; wc->closure.next = chand->waiting_for_config_closures; chand->waiting_for_config_closures = &wc->closure; } static int is_empty(void *p, int len) { char *ptr = p; int i; for (i = 0; i < len; i++) { if (ptr[i] != 0) return 0; } return 1; } static void started_call(void *arg, int iomgr_success) { call_data *calld = arg; grpc_transport_stream_op op; int have_waiting; gpr_mu_lock(&calld->mu_state); if (calld->state == CALL_CANCELLED && calld->subchannel_call != NULL) { memset(&op, 0, sizeof(op)); op.cancel_with_status = GRPC_STATUS_CANCELLED; gpr_mu_unlock(&calld->mu_state); grpc_subchannel_call_process_op(calld->subchannel_call, &op); } else if (calld->state == CALL_WAITING_FOR_CALL) { have_waiting = !is_empty(&calld->waiting_op, sizeof(calld->waiting_op)); if (calld->subchannel_call != NULL) { calld->state = CALL_ACTIVE; gpr_mu_unlock(&calld->mu_state); if (have_waiting) { grpc_subchannel_call_process_op(calld->subchannel_call, &calld->waiting_op); } } else { calld->state = CALL_CANCELLED; gpr_mu_unlock(&calld->mu_state); if (have_waiting) { handle_op_after_cancellation(calld->elem, &calld->waiting_op); } } } else { GPR_ASSERT(calld->state == CALL_CANCELLED); gpr_mu_unlock(&calld->mu_state); } } static void picked_target(void *arg, int iomgr_success) { call_data *calld = arg; grpc_pollset *pollset; if (calld->picked_channel == NULL) { /* treat this like a cancellation */ calld->waiting_op.cancel_with_status = GRPC_STATUS_UNAVAILABLE; perform_transport_stream_op(calld->elem, &calld->waiting_op, 1); } else { gpr_mu_lock(&calld->mu_state); if (calld->state == CALL_CANCELLED) { gpr_mu_unlock(&calld->mu_state); handle_op_after_cancellation(calld->elem, &calld->waiting_op); } else { GPR_ASSERT(calld->state == CALL_WAITING_FOR_PICK); calld->state = CALL_WAITING_FOR_CALL; pollset = calld->waiting_op.bind_pollset; gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init(&calld->async_setup_task, started_call, calld); grpc_subchannel_create_call(calld->picked_channel, pollset, &calld->subchannel_call, &calld->async_setup_task); } } } static grpc_iomgr_closure *merge_into_waiting_op( grpc_call_element *elem, grpc_transport_stream_op *new_op) { call_data *calld = elem->call_data; grpc_iomgr_closure *consumed_op = NULL; grpc_transport_stream_op *waiting_op = &calld->waiting_op; GPR_ASSERT((waiting_op->send_ops != NULL) + (new_op->send_ops != NULL) <= 1); GPR_ASSERT((waiting_op->recv_ops != NULL) + (new_op->recv_ops != NULL) <= 1); if (new_op->send_ops != NULL) { waiting_op->send_ops = new_op->send_ops; waiting_op->is_last_send = new_op->is_last_send; waiting_op->on_done_send = new_op->on_done_send; } if (new_op->recv_ops != NULL) { waiting_op->recv_ops = new_op->recv_ops; waiting_op->recv_state = new_op->recv_state; waiting_op->on_done_recv = new_op->on_done_recv; } if (new_op->on_consumed != NULL) { if (waiting_op->on_consumed != NULL) { consumed_op = waiting_op->on_consumed; } waiting_op->on_consumed = new_op->on_consumed; } if (new_op->cancel_with_status != GRPC_STATUS_OK) { waiting_op->cancel_with_status = new_op->cancel_with_status; } return consumed_op; } static char *cc_get_peer(grpc_call_element *elem) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_subchannel_call *subchannel_call; char *result; gpr_mu_lock(&calld->mu_state); if (calld->state == CALL_ACTIVE) { subchannel_call = calld->subchannel_call; GRPC_SUBCHANNEL_CALL_REF(subchannel_call, "get_peer"); gpr_mu_unlock(&calld->mu_state); result = grpc_subchannel_call_get_peer(subchannel_call); GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "get_peer"); return result; } else { gpr_mu_unlock(&calld->mu_state); return grpc_channel_get_target(chand->master); } } static void perform_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op, int continuation) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_subchannel_call *subchannel_call; grpc_lb_policy *lb_policy; grpc_transport_stream_op op2; grpc_iomgr_closure *consumed_op = NULL; GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); gpr_mu_lock(&calld->mu_state); switch (calld->state) { case CALL_ACTIVE: GPR_ASSERT(!continuation); subchannel_call = calld->subchannel_call; gpr_mu_unlock(&calld->mu_state); grpc_subchannel_call_process_op(subchannel_call, op); break; case CALL_CANCELLED: gpr_mu_unlock(&calld->mu_state); handle_op_after_cancellation(elem, op); break; case CALL_WAITING_FOR_SEND: GPR_ASSERT(!continuation); consumed_op = merge_into_waiting_op(elem, op); if (!calld->waiting_op.send_ops && calld->waiting_op.cancel_with_status == GRPC_STATUS_OK) { gpr_mu_unlock(&calld->mu_state); break; } *op = calld->waiting_op; memset(&calld->waiting_op, 0, sizeof(calld->waiting_op)); continuation = 1; /* fall through */ case CALL_WAITING_FOR_CONFIG: case CALL_WAITING_FOR_PICK: case CALL_WAITING_FOR_CALL: if (!continuation) { if (op->cancel_with_status != GRPC_STATUS_OK) { calld->state = CALL_CANCELLED; op2 = calld->waiting_op; memset(&calld->waiting_op, 0, sizeof(calld->waiting_op)); if (op->on_consumed) { calld->waiting_op.on_consumed = op->on_consumed; op->on_consumed = NULL; } else if (op2.on_consumed) { calld->waiting_op.on_consumed = op2.on_consumed; op2.on_consumed = NULL; } gpr_mu_unlock(&calld->mu_state); handle_op_after_cancellation(elem, op); handle_op_after_cancellation(elem, &op2); } else { consumed_op = merge_into_waiting_op(elem, op); gpr_mu_unlock(&calld->mu_state); } break; } /* fall through */ case CALL_CREATED: if (op->cancel_with_status != GRPC_STATUS_OK) { calld->state = CALL_CANCELLED; gpr_mu_unlock(&calld->mu_state); handle_op_after_cancellation(elem, op); } else { calld->waiting_op = *op; if (op->send_ops == NULL) { /* need to have some send ops before we can select the lb target */ calld->state = CALL_WAITING_FOR_SEND; gpr_mu_unlock(&calld->mu_state); } else { gpr_mu_lock(&chand->mu_config); lb_policy = chand->lb_policy; if (lb_policy) { grpc_transport_stream_op *op = &calld->waiting_op; grpc_pollset *bind_pollset = op->bind_pollset; grpc_metadata_batch *initial_metadata = &op->send_ops->ops[0].data.metadata; GRPC_LB_POLICY_REF(lb_policy, "pick"); gpr_mu_unlock(&chand->mu_config); calld->state = CALL_WAITING_FOR_PICK; GPR_ASSERT(op->bind_pollset); GPR_ASSERT(op->send_ops); GPR_ASSERT(op->send_ops->nops >= 1); GPR_ASSERT(op->send_ops->ops[0].type == GRPC_OP_METADATA); gpr_mu_unlock(&calld->mu_state); grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, calld); grpc_lb_policy_pick(lb_policy, bind_pollset, initial_metadata, &calld->picked_channel, &calld->async_setup_task); GRPC_LB_POLICY_UNREF(lb_policy, "pick"); } else if (chand->resolver != NULL) { calld->state = CALL_WAITING_FOR_CONFIG; add_to_lb_policy_wait_queue_locked_state_config(elem); if (!chand->started_resolving && chand->resolver != NULL) { GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); chand->started_resolving = 1; grpc_resolver_next(chand->resolver, &chand->incoming_configuration, &chand->on_config_changed); } gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&calld->mu_state); } else { calld->state = CALL_CANCELLED; gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&calld->mu_state); handle_op_after_cancellation(elem, op); } } } break; } if (consumed_op != NULL) { consumed_op->cb(consumed_op->cb_arg, 1); } } static void cc_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { perform_transport_stream_op(elem, op, 0); } static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state); static void on_lb_policy_state_changed(void *arg, int iomgr_success) { lb_policy_connectivity_watcher *w = arg; gpr_mu_lock(&w->chand->mu_config); /* check if the notification is for a stale policy */ if (w->lb_policy == w->chand->lb_policy) { grpc_connectivity_state_set(&w->chand->state_tracker, w->state, "lb_changed"); if (w->state != GRPC_CHANNEL_FATAL_FAILURE) { watch_lb_policy(w->chand, w->lb_policy, w->state); } } gpr_mu_unlock(&w->chand->mu_config); GRPC_CHANNEL_INTERNAL_UNREF(w->chand->master, "watch_lb_policy"); gpr_free(w); } static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state) { lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy"); w->chand = chand; grpc_iomgr_closure_init(&w->on_changed, on_lb_policy_state_changed, w); w->state = current_state; w->lb_policy = lb_policy; grpc_lb_policy_notify_on_state_change(lb_policy, &w->state, &w->on_changed); } static void cc_on_config_changed(void *arg, int iomgr_success) { channel_data *chand = arg; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; grpc_resolver *old_resolver; grpc_iomgr_closure *wakeup_closures = NULL; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; int exit_idle = 0; if (chand->incoming_configuration != NULL) { lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); if (lb_policy != NULL) { GRPC_LB_POLICY_REF(lb_policy, "channel"); GRPC_LB_POLICY_REF(lb_policy, "config_change"); state = grpc_lb_policy_check_connectivity(lb_policy); } grpc_client_config_unref(chand->incoming_configuration); } chand->incoming_configuration = NULL; gpr_mu_lock(&chand->mu_config); old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) { wakeup_closures = chand->waiting_for_config_closures; chand->waiting_for_config_closures = NULL; } if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); exit_idle = 1; chand->exit_idle_when_lb_policy_arrives = 0; } if (iomgr_success && chand->resolver) { grpc_resolver *resolver = chand->resolver; GRPC_RESOLVER_REF(resolver, "channel-next"); grpc_connectivity_state_set(&chand->state_tracker, state, "new_lb+resolver"); gpr_mu_unlock(&chand->mu_config); GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); grpc_resolver_next(resolver, &chand->incoming_configuration, &chand->on_config_changed); GRPC_RESOLVER_UNREF(resolver, "channel-next"); if (lb_policy != NULL) { watch_lb_policy(chand, lb_policy, state); } } else { old_resolver = chand->resolver; chand->resolver = NULL; grpc_connectivity_state_set(&chand->state_tracker, GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone"); gpr_mu_unlock(&chand->mu_config); if (old_resolver != NULL) { grpc_resolver_shutdown(old_resolver); GRPC_RESOLVER_UNREF(old_resolver, "channel"); } } if (exit_idle) { grpc_lb_policy_exit_idle(lb_policy); GRPC_LB_POLICY_UNREF(lb_policy, "exit_idle"); } if (old_lb_policy != NULL) { grpc_lb_policy_shutdown(old_lb_policy); GRPC_LB_POLICY_UNREF(old_lb_policy, "channel"); } while (wakeup_closures) { grpc_iomgr_closure *next = wakeup_closures->next; wakeup_closures->cb(wakeup_closures->cb_arg, 1); wakeup_closures = next; } if (lb_policy != NULL) { GRPC_LB_POLICY_UNREF(lb_policy, "config_change"); } GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver"); } static void cc_start_transport_op(grpc_channel_element *elem, grpc_transport_op *op) { grpc_lb_policy *lb_policy = NULL; channel_data *chand = elem->channel_data; grpc_resolver *destroy_resolver = NULL; grpc_iomgr_closure *on_consumed = op->on_consumed; op->on_consumed = NULL; GPR_ASSERT(op->set_accept_stream == NULL); GPR_ASSERT(op->bind_pollset == NULL); gpr_mu_lock(&chand->mu_config); if (op->on_connectivity_state_change != NULL) { grpc_connectivity_state_notify_on_state_change( &chand->state_tracker, op->connectivity_state, op->on_connectivity_state_change); op->on_connectivity_state_change = NULL; op->connectivity_state = NULL; } if (!is_empty(op, sizeof(*op))) { lb_policy = chand->lb_policy; if (lb_policy) { GRPC_LB_POLICY_REF(lb_policy, "broadcast"); } } if (op->disconnect && chand->resolver != NULL) { grpc_connectivity_state_set(&chand->state_tracker, GRPC_CHANNEL_FATAL_FAILURE, "disconnect"); destroy_resolver = chand->resolver; chand->resolver = NULL; if (chand->lb_policy != NULL) { grpc_lb_policy_shutdown(chand->lb_policy); GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel"); chand->lb_policy = NULL; } } gpr_mu_unlock(&chand->mu_config); if (destroy_resolver) { grpc_resolver_shutdown(destroy_resolver); GRPC_RESOLVER_UNREF(destroy_resolver, "channel"); } if (lb_policy) { grpc_lb_policy_broadcast(lb_policy, op); GRPC_LB_POLICY_UNREF(lb_policy, "broadcast"); } if (on_consumed) { grpc_iomgr_add_callback(on_consumed); } } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { call_data *calld = elem->call_data; /* TODO(ctiller): is there something useful we can do here? */ GPR_ASSERT(initial_op == NULL); GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GPR_ASSERT(server_transport_data == NULL); gpr_mu_init(&calld->mu_state); calld->elem = elem; calld->state = CALL_CREATED; calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { call_data *calld = elem->call_data; grpc_subchannel_call *subchannel_call; /* if the call got activated, we need to destroy the child stack also, and remove it from the in-flight requests tracked by the child_entry we picked */ gpr_mu_lock(&calld->mu_state); switch (calld->state) { case CALL_ACTIVE: subchannel_call = calld->subchannel_call; gpr_mu_unlock(&calld->mu_state); GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "client_channel"); break; case CALL_CREATED: case CALL_CANCELLED: gpr_mu_unlock(&calld->mu_state); break; case CALL_WAITING_FOR_PICK: case CALL_WAITING_FOR_CONFIG: case CALL_WAITING_FOR_CALL: case CALL_WAITING_FOR_SEND: gpr_log(GPR_ERROR, "should never reach here"); abort(); break; } } /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *metadata_context, int is_first, int is_last) { channel_data *chand = elem->channel_data; memset(chand, 0, sizeof(*chand)); GPR_ASSERT(is_last); GPR_ASSERT(elem->filter == &grpc_client_channel_filter); gpr_mu_init(&chand->mu_config); chand->mdctx = metadata_context; chand->master = master; grpc_pollset_set_init(&chand->pollset_set); grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed, chand); grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel"); } /* Destructor for channel_data */ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *chand = elem->channel_data; if (chand->resolver != NULL) { grpc_resolver_shutdown(chand->resolver); GRPC_RESOLVER_UNREF(chand->resolver, "channel"); } if (chand->lb_policy != NULL) { GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel"); } grpc_connectivity_state_destroy(&chand->state_tracker); grpc_pollset_set_destroy(&chand->pollset_set); gpr_mu_destroy(&chand->mu_config); } const grpc_channel_filter grpc_client_channel_filter = { cc_start_transport_stream_op, cc_start_transport_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, cc_get_peer, "client-channel", }; void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack, grpc_resolver *resolver) { /* post construction initialization: set the transport setup pointer */ grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack); channel_data *chand = elem->channel_data; gpr_mu_lock(&chand->mu_config); GPR_ASSERT(!chand->resolver); chand->resolver = resolver; GRPC_RESOLVER_REF(resolver, "channel"); if (chand->waiting_for_config_closures != NULL || chand->exit_idle_when_lb_policy_arrives) { chand->started_resolving = 1; GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); grpc_resolver_next(resolver, &chand->incoming_configuration, &chand->on_config_changed); } gpr_mu_unlock(&chand->mu_config); } grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_channel_element *elem, int try_to_connect) { channel_data *chand = elem->channel_data; grpc_connectivity_state out; gpr_mu_lock(&chand->mu_config); out = grpc_connectivity_state_check(&chand->state_tracker); if (out == GRPC_CHANNEL_IDLE && try_to_connect) { if (chand->lb_policy != NULL) { grpc_lb_policy_exit_idle(chand->lb_policy); } else { chand->exit_idle_when_lb_policy_arrives = 1; if (!chand->started_resolving && chand->resolver != NULL) { GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); chand->started_resolving = 1; grpc_resolver_next(chand->resolver, &chand->incoming_configuration, &chand->on_config_changed); } } } gpr_mu_unlock(&chand->mu_config); return out; } void grpc_client_channel_watch_connectivity_state( grpc_channel_element *elem, grpc_connectivity_state *state, grpc_iomgr_closure *on_complete) { channel_data *chand = elem->channel_data; gpr_mu_lock(&chand->mu_config); grpc_connectivity_state_notify_on_state_change(&chand->state_tracker, state, on_complete); gpr_mu_unlock(&chand->mu_config); } grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set( grpc_channel_element *elem) { channel_data *chand = elem->channel_data; return &chand->pollset_set; } void grpc_client_channel_add_interested_party(grpc_channel_element *elem, grpc_pollset *pollset) { channel_data *chand = elem->channel_data; grpc_pollset_set_add_pollset(&chand->pollset_set, pollset); } void grpc_client_channel_del_interested_party(grpc_channel_element *elem, grpc_pollset *pollset) { channel_data *chand = elem->channel_data; grpc_pollset_set_del_pollset(&chand->pollset_set, pollset); } grpc-0.11.1/src/core/channel/http_server_filter.c0000644000175000017500000002641312600663151022132 0ustar apollockapollock/* * * 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/channel/http_server_filter.h" #include #include #include typedef struct call_data { gpr_uint8 got_initial_metadata; gpr_uint8 seen_path; gpr_uint8 seen_post; gpr_uint8 sent_status; gpr_uint8 seen_scheme; gpr_uint8 seen_te_trailers; gpr_uint8 seen_authority; grpc_linked_mdelem status; grpc_linked_mdelem content_type; grpc_stream_op_buffer *recv_ops; /** Closure to call when finished with the hs_on_recv hook */ grpc_iomgr_closure *on_done_recv; /** Receive closures are chained: we inject this closure as the on_done_recv up-call on transport_op, and remember to call our on_done_recv member after handling it. */ grpc_iomgr_closure hs_on_recv; } call_data; typedef struct channel_data { grpc_mdelem *te_trailers; grpc_mdelem *method_post; grpc_mdelem *http_scheme; grpc_mdelem *https_scheme; /* TODO(klempner): Remove this once we stop using it */ grpc_mdelem *grpc_scheme; grpc_mdelem *content_type; grpc_mdelem *status_ok; grpc_mdelem *status_not_found; grpc_mdstr *path_key; grpc_mdstr *authority_key; grpc_mdstr *host_key; grpc_mdctx *mdctx; } channel_data; static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; channel_data *channeld = elem->channel_data; call_data *calld = elem->call_data; /* Check if it is one of the headers we care about. */ if (md == channeld->te_trailers || md == channeld->method_post || md == channeld->http_scheme || md == channeld->https_scheme || md == channeld->grpc_scheme || md == channeld->content_type) { /* swallow it */ if (md == channeld->method_post) { calld->seen_post = 1; } else if (md->key == channeld->http_scheme->key) { calld->seen_scheme = 1; } else if (md == channeld->te_trailers) { calld->seen_te_trailers = 1; } /* TODO(klempner): Track that we've seen all the headers we should require */ return NULL; } else if (md->key == channeld->content_type->key) { if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) == 0) { /* Although the C implementation doesn't (currently) generate them, any custom +-suffix is explicitly valid. */ /* TODO(klempner): We should consider preallocating common values such as +proto or +json, or at least stashing them if we see them. */ /* TODO(klempner): Should we be surfacing this to application code? */ } else { /* TODO(klempner): We're currently allowing this, but we shouldn't see it without a proxy so log for now. */ gpr_log(GPR_INFO, "Unexpected content-type %s", channeld->content_type->key); } return NULL; } else if (md->key == channeld->te_trailers->key || md->key == channeld->method_post->key || md->key == channeld->http_scheme->key || md->key == channeld->content_type->key) { gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)); /* swallow it and error everything out. */ /* TODO(klempner): We ought to generate more descriptive error messages on the wire here. */ grpc_call_element_send_cancel(elem); return NULL; } else if (md->key == channeld->path_key) { if (calld->seen_path) { gpr_log(GPR_ERROR, "Received :path twice"); return NULL; } calld->seen_path = 1; return md; } else if (md->key == channeld->authority_key) { calld->seen_authority = 1; return md; } else if (md->key == channeld->host_key) { /* translate host to :authority since :authority may be omitted */ grpc_mdelem *authority = grpc_mdelem_from_metadata_strings( channeld->mdctx, GRPC_MDSTR_REF(channeld->authority_key), GRPC_MDSTR_REF(md->value)); GRPC_MDELEM_UNREF(md); calld->seen_authority = 1; return authority; } else { return md; } } static void hs_on_recv(void *user_data, int success) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; if (success) { size_t i; size_t nops = calld->recv_ops->nops; grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; calld->got_initial_metadata = 1; grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); /* Have we seen the required http2 transport headers? (:method, :scheme, content-type, with :path and :authority covered at the channel level right now) */ if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers && calld->seen_path && calld->seen_authority) { /* do nothing */ } else { if (!calld->seen_path) { gpr_log(GPR_ERROR, "Missing :path header"); } if (!calld->seen_authority) { gpr_log(GPR_ERROR, "Missing :authority header"); } if (!calld->seen_post) { gpr_log(GPR_ERROR, "Missing :method header"); } if (!calld->seen_scheme) { gpr_log(GPR_ERROR, "Missing :scheme header"); } if (!calld->seen_te_trailers) { gpr_log(GPR_ERROR, "Missing te trailers header"); } /* Error this call out */ success = 0; grpc_call_element_send_cancel(elem); } } } calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } static void hs_mutate_op(grpc_call_element *elem, grpc_transport_stream_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; size_t i; if (op->send_ops && !calld->sent_status) { size_t nops = op->send_ops->nops; grpc_stream_op *ops = op->send_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; calld->sent_status = 1; grpc_metadata_batch_add_head(&op->data.metadata, &calld->status, GRPC_MDELEM_REF(channeld->status_ok)); grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type, GRPC_MDELEM_REF(channeld->content_type)); break; } } if (op->recv_ops && !calld->got_initial_metadata) { /* substitute our callback for the higher callback */ calld->recv_ops = op->recv_ops; calld->on_done_recv = op->on_done_recv; op->on_done_recv = &calld->hs_on_recv; } } static void hs_start_transport_op(grpc_call_element *elem, grpc_transport_stream_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); hs_mutate_op(elem, op); grpc_call_next_op(elem, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; /* initialize members */ memset(calld, 0, sizeof(*calld)); grpc_iomgr_closure_init(&calld->hs_on_recv, hs_on_recv, elem); if (initial_op) hs_mutate_op(elem, initial_op); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) {} /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; /* The first and the last filters tend to be implemented differently to handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!is_first); GPR_ASSERT(!is_last); /* initialize members */ channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers"); channeld->status_ok = grpc_mdelem_from_strings(mdctx, ":status", "200"); channeld->status_not_found = grpc_mdelem_from_strings(mdctx, ":status", "404"); channeld->method_post = grpc_mdelem_from_strings(mdctx, ":method", "POST"); channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http"); channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https"); channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc"); channeld->path_key = grpc_mdstr_from_string(mdctx, ":path", 0); channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority", 0); channeld->host_key = grpc_mdstr_from_string(mdctx, "host", 0); channeld->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); channeld->mdctx = mdctx; } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; GRPC_MDELEM_UNREF(channeld->te_trailers); GRPC_MDELEM_UNREF(channeld->status_ok); GRPC_MDELEM_UNREF(channeld->status_not_found); GRPC_MDELEM_UNREF(channeld->method_post); GRPC_MDELEM_UNREF(channeld->http_scheme); GRPC_MDELEM_UNREF(channeld->https_scheme); GRPC_MDELEM_UNREF(channeld->grpc_scheme); GRPC_MDELEM_UNREF(channeld->content_type); GRPC_MDSTR_UNREF(channeld->path_key); GRPC_MDSTR_UNREF(channeld->authority_key); GRPC_MDSTR_UNREF(channeld->host_key); } const grpc_channel_filter grpc_http_server_filter = { hs_start_transport_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "http-server"}; grpc-0.11.1/src/core/channel/http_server_filter.h0000644000175000017500000000357112600663151022137 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H #define GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H #include "src/core/channel/channel_stack.h" /* Processes metadata on the client side for HTTP2 transports */ extern const grpc_channel_filter grpc_http_server_filter; #endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H */ grpc-0.11.1/src/core/channel/channel_stack.h0000644000175000017500000002077512600663151021027 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H #define GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H /* A channel filter defines how operations on a channel are implemented. Channel filters are chained together to create full channels, and if those chains are linear, then channel stacks provide a mechanism to minimize allocations for that chain. Call stacks are created by channel stacks and represent the per-call data for that stack. */ #include #include #include #include "src/core/debug/trace.h" #include "src/core/transport/transport.h" typedef struct grpc_channel_element grpc_channel_element; typedef struct grpc_call_element grpc_call_element; /* Channel filters specify: 1. the amount of memory needed in the channel & call (via the sizeof_XXX members) 2. functions to initialize and destroy channel & call data (init_XXX, destroy_XXX) 3. functions to implement call operations and channel operations (call_op, channel_op) 4. a name, which is useful when debugging Members are laid out in approximate frequency of use order. */ typedef struct { /* Called to eg. send/receive data on a call. See grpc_call_next_op on how to call the next element in the stack */ void (*start_transport_stream_op)(grpc_call_element *elem, grpc_transport_stream_op *op); /* Called to handle channel level operations - e.g. new calls, or transport closure. See grpc_channel_next_op on how to call the next element in the stack */ void (*start_transport_op)(grpc_channel_element *elem, grpc_transport_op *op); /* sizeof(per call data) */ size_t sizeof_call_data; /* Initialize per call data. elem is initialized at the start of the call, and elem->call_data is what needs initializing. The filter does not need to do any chaining. server_transport_data is an opaque pointer. If it is NULL, this call is on a client; if it is non-NULL, then it points to memory owned by the transport and is on the server. Most filters want to ignore this argument.*/ void (*init_call_elem)(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op); /* Destroy per call data. The filter does not need to do any chaining */ void (*destroy_call_elem)(grpc_call_element *elem); /* sizeof(per channel data) */ size_t sizeof_channel_data; /* Initialize per-channel data. elem is initialized at the start of the call, and elem->channel_data is what needs initializing. is_first, is_last designate this elements position in the stack, and are useful for asserting correct configuration by upper layer code. The filter does not need to do any chaining */ void (*init_channel_elem)(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *metadata_context, int is_first, int is_last); /* Destroy per channel data. The filter does not need to do any chaining */ void (*destroy_channel_elem)(grpc_channel_element *elem); /* Implement grpc_call_get_peer() */ char *(*get_peer)(grpc_call_element *elem); /* The name of this filter */ const char *name; } grpc_channel_filter; /* A channel_element tracks its filter and the filter requested memory within a channel allocation */ struct grpc_channel_element { const grpc_channel_filter *filter; void *channel_data; }; /* A call_element tracks its filter, the filter requested memory within a channel allocation, and the filter requested memory within a call allocation */ struct grpc_call_element { const grpc_channel_filter *filter; void *channel_data; void *call_data; }; /* A channel stack tracks a set of related filters for one channel, and guarantees they live within a single malloc() allocation */ typedef struct { size_t count; /* Memory required for a call stack (computed at channel stack initialization) */ size_t call_stack_size; } grpc_channel_stack; /* A call stack tracks a set of related filters for one call, and guarantees they live within a single malloc() allocation */ typedef struct { size_t count; } grpc_call_stack; /* Get a channel element given a channel stack and its index */ grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack, size_t i); /* Get the last channel element in a channel stack */ grpc_channel_element *grpc_channel_stack_last_element( grpc_channel_stack *stack); /* Get a call stack element given a call stack and an index */ grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i); /* Determine memory required for a channel stack containing a set of filters */ size_t grpc_channel_stack_size(const grpc_channel_filter **filters, size_t filter_count); /* Initialize a channel stack given some filters */ void grpc_channel_stack_init(const grpc_channel_filter **filters, size_t filter_count, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *metadata_context, grpc_channel_stack *stack); /* Destroy a channel stack */ void grpc_channel_stack_destroy(grpc_channel_stack *stack); /* Initialize a call stack given a channel stack. transport_server_data is expected to be NULL on a client, or an opaque transport owned pointer on the server. */ void grpc_call_stack_init(grpc_channel_stack *channel_stack, const void *transport_server_data, grpc_transport_stream_op *initial_op, grpc_call_stack *call_stack); /* Destroy a call stack */ void grpc_call_stack_destroy(grpc_call_stack *stack); /* Call the next operation in a call stack */ void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op); /* Call the next operation (depending on call directionality) in a channel stack */ void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op); /* Pass through a request to get_peer to the next child element */ char *grpc_call_next_get_peer(grpc_call_element *elem); /* Given the top element of a channel stack, get the channel stack itself */ grpc_channel_stack *grpc_channel_stack_from_top_element( grpc_channel_element *elem); /* Given the top element of a call stack, get the call stack itself */ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem); void grpc_call_log_op(char *file, int line, gpr_log_severity severity, grpc_call_element *elem, grpc_transport_stream_op *op); void grpc_call_element_send_cancel(grpc_call_element *cur_elem); extern int grpc_trace_channel; #define GRPC_CALL_LOG_OP(sev, elem, op) \ if (grpc_trace_channel) grpc_call_log_op(sev, elem, op) #endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H */ grpc-0.11.1/src/core/channel/compress_filter.h0000644000175000017500000000554112600663151021424 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H #define GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H #include "src/core/channel/channel_stack.h" #define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request" /** Compression filter for outgoing data. * * See for the available compression settings. * * Compression settings may come from: * - Channel configuration, as established at channel creation time. * - The metadata accompanying the outgoing data to be compressed. This is * taken as a request only. We may choose not to honor it. The metadata key * is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY. * * Compression can be disabled for concrete messages (for instance in order to * prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in * the BEGIN_MESSAGE flags. * * The attempted compression mechanism is added to the resulting initial * metadata under the'grpc-encoding' key. * * If compression is actually performed, BEGIN_MESSAGE's flag is modified to * incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the * aforementioned 'grpc-encoding' metadata value, data will pass through * uncompressed. */ extern const grpc_channel_filter grpc_compress_filter; #endif /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */ grpc-0.11.1/src/core/channel/connected_channel.c0000644000175000017500000001421312600663151021645 0ustar apollockapollock/* * * 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/channel/connected_channel.h" #include #include #include #include "src/core/support/string.h" #include "src/core/transport/transport.h" #include #include #include #include #define MAX_BUFFER_LENGTH 8192 typedef struct connected_channel_channel_data { grpc_transport *transport; } channel_data; typedef struct connected_channel_call_data { void *unused; } call_data; /* We perform a small hack to locate transport data alongside the connected channel data in call allocations, to allow everything to be pulled in minimal cache line requests */ #define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld) + 1)) #define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \ (((call_data *)(transport_stream)) - 1) /* Intercept a call operation and either push it directly up or translate it into transport stream operations */ static void con_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); grpc_transport_perform_stream_op(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), op); } static void con_start_transport_op(grpc_channel_element *elem, grpc_transport_op *op) { channel_data *chand = elem->channel_data; grpc_transport_perform_op(chand->transport, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; int r; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); r = grpc_transport_init_stream(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), server_transport_data, initial_op); GPR_ASSERT(r == 0); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); grpc_transport_destroy_stream(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld)); } /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { channel_data *cd = (channel_data *)elem->channel_data; GPR_ASSERT(is_last); GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); cd->transport = NULL; } /* Destructor for channel_data */ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *cd = (channel_data *)elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); grpc_transport_destroy(cd->transport); } static char *con_get_peer(grpc_call_element *elem) { channel_data *chand = elem->channel_data; return grpc_transport_get_peer(chand->transport); } const grpc_channel_filter grpc_connected_channel_filter = { con_start_transport_stream_op, con_start_transport_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, con_get_peer, "connected", }; void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack, grpc_transport *transport) { /* Assumes that the connected channel filter is always the last filter in a channel stack */ grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack); channel_data *cd = (channel_data *)elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GPR_ASSERT(cd->transport == NULL); cd->transport = transport; /* HACK(ctiller): increase call stack size for the channel to make space for channel data. We need a cleaner (but performant) way to do this, and I'm not sure what that is yet. This is only "safe" because call stacks place no additional data after the last call element, and the last call element MUST be the connected channel. */ channel_stack->call_stack_size += grpc_transport_stream_size(transport); } grpc-0.11.1/src/core/security/0000755000175000017500000000000012600663151016305 5ustar apollockapollockgrpc-0.11.1/src/core/security/google_default_credentials.c0000644000175000017500000001736412600663151024021 0ustar apollockapollock/* * * 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/security/credentials.h" #include #include #include #include #include "src/core/httpcli/httpcli.h" #include "src/core/support/env.h" #include "src/core/support/file.h" /* -- Constants. -- */ #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal" /* -- Default credentials. -- */ static grpc_credentials *default_credentials = NULL; static int compute_engine_detection_done = 0; static gpr_mu g_mu; static gpr_once g_once = GPR_ONCE_INIT; static void init_default_credentials(void) { gpr_mu_init(&g_mu); } typedef struct { grpc_pollset pollset; int is_done; int success; } compute_engine_detector; static void on_compute_engine_detection_http_response( void *user_data, const grpc_httpcli_response *response) { compute_engine_detector *detector = (compute_engine_detector *)user_data; if (response != NULL && response->status == 200 && response->hdr_count > 0) { /* Internet providers can return a generic response to all requests, so it is necessary to check that metadata header is present also. */ size_t i; for (i = 0; i < response->hdr_count; i++) { grpc_httpcli_header *header = &response->hdrs[i]; if (strcmp(header->key, "Metadata-Flavor") == 0 && strcmp(header->value, "Google") == 0) { detector->success = 1; break; } } } gpr_mu_lock(GRPC_POLLSET_MU(&detector->pollset)); detector->is_done = 1; grpc_pollset_kick(&detector->pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset)); } static void destroy_pollset(void *p) { grpc_pollset_destroy(p); } static int is_stack_running_on_compute_engine(void) { compute_engine_detector detector; grpc_httpcli_request request; grpc_httpcli_context context; /* The http call is local. If it takes more than one sec, it is for sure not on compute engine. */ gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN); grpc_pollset_init(&detector.pollset); detector.is_done = 0; detector.success = 0; memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST; request.path = "/"; grpc_httpcli_context_init(&context); grpc_httpcli_get( &context, &detector.pollset, &request, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay), on_compute_engine_detection_http_response, &detector); /* Block until we get the response. This is not ideal but this should only be called once for the lifetime of the process by the default credentials. */ gpr_mu_lock(GRPC_POLLSET_MU(&detector.pollset)); while (!detector.is_done) { grpc_pollset_worker worker; grpc_pollset_work(&detector.pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), gpr_inf_future(GPR_CLOCK_MONOTONIC)); } gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset)); grpc_httpcli_context_destroy(&context); grpc_pollset_shutdown(&detector.pollset, destroy_pollset, &detector.pollset); return detector.success; } /* Takes ownership of creds_path if not NULL. */ static grpc_credentials *create_default_creds_from_path(char *creds_path) { grpc_json *json = NULL; grpc_auth_json_key key; grpc_auth_refresh_token token; grpc_credentials *result = NULL; gpr_slice creds_data = gpr_empty_slice(); int file_ok = 0; if (creds_path == NULL) goto end; creds_data = gpr_load_file(creds_path, 0, &file_ok); if (!file_ok) goto end; json = grpc_json_parse_string_with_len( (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data)); if (json == NULL) goto end; /* First, try an auth json key. */ key = grpc_auth_json_key_create_from_json(json); if (grpc_auth_json_key_is_valid(&key)) { result = grpc_service_account_jwt_access_credentials_create_from_auth_json_key( key, grpc_max_auth_token_lifetime); goto end; } /* Then try a refresh token if the auth json key was invalid. */ token = grpc_auth_refresh_token_create_from_json(json); if (grpc_auth_refresh_token_is_valid(&token)) { result = grpc_refresh_token_credentials_create_from_auth_refresh_token(token); goto end; } end: if (creds_path != NULL) gpr_free(creds_path); gpr_slice_unref(creds_data); if (json != NULL) grpc_json_destroy(json); return result; } grpc_credentials *grpc_google_default_credentials_create(void) { grpc_credentials *result = NULL; int serving_cached_credentials = 0; gpr_once_init(&g_once, init_default_credentials); gpr_mu_lock(&g_mu); if (default_credentials != NULL) { result = grpc_credentials_ref(default_credentials); serving_cached_credentials = 1; goto end; } /* First, try the environment variable. */ result = create_default_creds_from_path( gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR)); if (result != NULL) goto end; /* Then the well-known file. */ result = create_default_creds_from_path( grpc_get_well_known_google_credentials_file_path()); if (result != NULL) goto end; /* At last try to see if we're on compute engine (do the detection only once since it requires a network test). */ if (!compute_engine_detection_done) { int need_compute_engine_creds = is_stack_running_on_compute_engine(); compute_engine_detection_done = 1; if (need_compute_engine_creds) { result = grpc_google_compute_engine_credentials_create(NULL); } } end: if (!serving_cached_credentials && result != NULL) { /* Blend with default ssl credentials and add a global reference so that it can be cached and re-served. */ grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); default_credentials = grpc_credentials_ref( grpc_composite_credentials_create(ssl_creds, result, NULL)); GPR_ASSERT(default_credentials != NULL); grpc_credentials_unref(ssl_creds); grpc_credentials_unref(result); result = default_credentials; } gpr_mu_unlock(&g_mu); return result; } void grpc_flush_cached_google_default_credentials(void) { gpr_once_init(&g_once, init_default_credentials); gpr_mu_lock(&g_mu); if (default_credentials != NULL) { grpc_credentials_unref(default_credentials); default_credentials = NULL; } gpr_mu_unlock(&g_mu); } grpc-0.11.1/src/core/security/credentials_posix.c0000644000175000017500000000440712600663151022175 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_FILE #include "src/core/security/credentials.h" #include #include #include #include "src/core/support/env.h" #include "src/core/support/string.h" char *grpc_get_well_known_google_credentials_file_path(void) { char *result = NULL; char *home = gpr_getenv("HOME"); if (home == NULL) { gpr_log(GPR_ERROR, "Could not get HOME environment variable."); return NULL; } gpr_asprintf(&result, "%s/.config/%s/%s", home, GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); gpr_free(home); return result; } #endif /* GPR_POSIX_FILE */ grpc-0.11.1/src/core/security/json_token.c0000644000175000017500000003267312600663151020635 0ustar apollockapollock/* * * 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/security/json_token.h" #include #include #include #include #include "src/core/security/base64.h" #include "src/core/support/string.h" #include #include #include /* --- Constants. --- */ /* 1 hour max. */ const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0, GPR_TIMESPAN}; #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" #define GRPC_JWT_TYPE "JWT" /* --- Override for testing. --- */ static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL; /* --- grpc_auth_json_key. --- */ static const char *json_get_string_property(const grpc_json *json, const char *prop_name) { grpc_json *child; for (child = json->child; child != NULL; child = child->next) { if (strcmp(child->key, prop_name) == 0) break; } if (child == NULL || child->type != GRPC_JSON_STRING) { gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name); return NULL; } return child->value; } static int set_json_key_string_property(const grpc_json *json, const char *prop_name, char **json_key_field) { const char *prop_value = json_get_string_property(json, prop_name); if (prop_value == NULL) return 0; *json_key_field = gpr_strdup(prop_value); return 1; } int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) { return (json_key != NULL) && strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID); } grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) { grpc_auth_json_key result; BIO *bio = NULL; const char *prop_value; int success = 0; memset(&result, 0, sizeof(grpc_auth_json_key)); result.type = GRPC_AUTH_JSON_TYPE_INVALID; if (json == NULL) { gpr_log(GPR_ERROR, "Invalid json."); goto end; } prop_value = json_get_string_property(json, "type"); if (prop_value == NULL || strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) { goto end; } result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT; if (!set_json_key_string_property(json, "private_key_id", &result.private_key_id) || !set_json_key_string_property(json, "client_id", &result.client_id) || !set_json_key_string_property(json, "client_email", &result.client_email)) { goto end; } prop_value = json_get_string_property(json, "private_key"); if (prop_value == NULL) { goto end; } bio = BIO_new(BIO_s_mem()); success = BIO_puts(bio, prop_value); if ((success < 0) || ((size_t)success != strlen(prop_value))) { gpr_log(GPR_ERROR, "Could not write into openssl BIO."); goto end; } result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, ""); if (result.private_key == NULL) { gpr_log(GPR_ERROR, "Could not deserialize private key."); goto end; } success = 1; end: if (bio != NULL) BIO_free(bio); if (!success) grpc_auth_json_key_destruct(&result); return result; } grpc_auth_json_key grpc_auth_json_key_create_from_string( const char *json_string) { char *scratchpad = gpr_strdup(json_string); grpc_json *json = grpc_json_parse_string(scratchpad); grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json); if (json != NULL) grpc_json_destroy(json); gpr_free(scratchpad); return result; } void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) { if (json_key == NULL) return; json_key->type = GRPC_AUTH_JSON_TYPE_INVALID; if (json_key->client_id != NULL) { gpr_free(json_key->client_id); json_key->client_id = NULL; } if (json_key->private_key_id != NULL) { gpr_free(json_key->private_key_id); json_key->private_key_id = NULL; } if (json_key->client_email != NULL) { gpr_free(json_key->client_email); json_key->client_email = NULL; } if (json_key->private_key != NULL) { RSA_free(json_key->private_key); json_key->private_key = NULL; } } /* --- jwt encoding and signature. --- */ static grpc_json *create_child(grpc_json *brother, grpc_json *parent, const char *key, const char *value, grpc_json_type type) { grpc_json *child = grpc_json_create(type); if (brother) brother->next = child; if (!parent->child) parent->child = child; child->parent = parent; child->value = value; child->key = key; return child; } static char *encoded_jwt_header(const char *key_id, const char *algorithm) { grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *child = NULL; char *json_str = NULL; char *result = NULL; child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING); child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); create_child(child, json, "kid", key_id, GRPC_JSON_STRING); json_str = grpc_json_dump_to_string(json, 0); result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); gpr_free(json_str); grpc_json_destroy(json); return result; } static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope) { grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *child = NULL; char *json_str = NULL; char *result = NULL; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); gpr_timespec expiration = gpr_time_add(now, token_lifetime); char now_str[GPR_LTOA_MIN_BUFSIZE]; char expiration_str[GPR_LTOA_MIN_BUFSIZE]; if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime) > 0) { gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value."); expiration = gpr_time_add(now, grpc_max_auth_token_lifetime); } gpr_ltoa(now.tv_sec, now_str); gpr_ltoa(expiration.tv_sec, expiration_str); child = create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING); if (scope != NULL) { child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); } else { /* Unscoped JWTs need a sub field. */ child = create_child(child, json, "sub", json_key->client_email, GRPC_JSON_STRING); } child = create_child(child, json, "aud", audience, GRPC_JSON_STRING); child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER); create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER); json_str = grpc_json_dump_to_string(json, 0); result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); gpr_free(json_str); grpc_json_destroy(json); return result; } static char *dot_concat_and_free_strings(char *str1, char *str2) { size_t str1_len = strlen(str1); size_t str2_len = strlen(str2); size_t result_len = str1_len + 1 /* dot */ + str2_len; char *result = gpr_malloc(result_len + 1 /* NULL terminated */); char *current = result; memcpy(current, str1, str1_len); current += str1_len; *(current++) = '.'; memcpy(current, str2, str2_len); current += str2_len; GPR_ASSERT(current >= result); GPR_ASSERT((gpr_uintptr)(current - result) == result_len); *current = '\0'; gpr_free(str1); gpr_free(str2); return result; } const EVP_MD *openssl_digest_from_algorithm(const char *algorithm) { if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) { return EVP_sha256(); } else { gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm); return NULL; } } char *compute_and_encode_signature(const grpc_auth_json_key *json_key, const char *signature_algorithm, const char *to_sign) { const EVP_MD *md = openssl_digest_from_algorithm(signature_algorithm); EVP_MD_CTX *md_ctx = NULL; EVP_PKEY *key = EVP_PKEY_new(); size_t sig_len = 0; unsigned char *sig = NULL; char *result = NULL; if (md == NULL) return NULL; md_ctx = EVP_MD_CTX_create(); if (md_ctx == NULL) { gpr_log(GPR_ERROR, "Could not create MD_CTX"); goto end; } EVP_PKEY_set1_RSA(key, json_key->private_key); if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, key) != 1) { gpr_log(GPR_ERROR, "DigestInit failed."); goto end; } if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) { gpr_log(GPR_ERROR, "DigestUpdate failed."); goto end; } if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) { gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed."); goto end; } sig = gpr_malloc(sig_len); if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) { gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed."); goto end; } result = grpc_base64_encode(sig, sig_len, 1, 0); end: if (key != NULL) EVP_PKEY_free(key); if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); if (sig != NULL) gpr_free(sig); return result; } char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope) { if (g_jwt_encode_and_sign_override != NULL) { return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime, scope); } else { const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM; char *to_sign = dot_concat_and_free_strings( encoded_jwt_header(json_key->private_key_id, sig_algo), encoded_jwt_claim(json_key, audience, token_lifetime, scope)); char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign); if (sig == NULL) { gpr_free(to_sign); return NULL; } return dot_concat_and_free_strings(to_sign, sig); } } void grpc_jwt_encode_and_sign_set_override( grpc_jwt_encode_and_sign_override func) { g_jwt_encode_and_sign_override = func; } /* --- grpc_auth_refresh_token --- */ int grpc_auth_refresh_token_is_valid( const grpc_auth_refresh_token *refresh_token) { return (refresh_token != NULL) && strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID); } grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( const grpc_json *json) { grpc_auth_refresh_token result; const char *prop_value; int success = 0; memset(&result, 0, sizeof(grpc_auth_refresh_token)); result.type = GRPC_AUTH_JSON_TYPE_INVALID; if (json == NULL) { gpr_log(GPR_ERROR, "Invalid json."); goto end; } prop_value = json_get_string_property(json, "type"); if (prop_value == NULL || strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) { goto end; } result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER; if (!set_json_key_string_property(json, "client_secret", &result.client_secret) || !set_json_key_string_property(json, "client_id", &result.client_id) || !set_json_key_string_property(json, "refresh_token", &result.refresh_token)) { goto end; } success = 1; end: if (!success) grpc_auth_refresh_token_destruct(&result); return result; } grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( const char *json_string) { char *scratchpad = gpr_strdup(json_string); grpc_json *json = grpc_json_parse_string(scratchpad); grpc_auth_refresh_token result = grpc_auth_refresh_token_create_from_json(json); if (json != NULL) grpc_json_destroy(json); gpr_free(scratchpad); return result; } void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) { if (refresh_token == NULL) return; refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID; if (refresh_token->client_id != NULL) { gpr_free(refresh_token->client_id); refresh_token->client_id = NULL; } if (refresh_token->client_secret != NULL) { gpr_free(refresh_token->client_secret); refresh_token->client_secret = NULL; } if (refresh_token->refresh_token != NULL) { gpr_free(refresh_token->refresh_token); refresh_token->refresh_token = NULL; } } grpc-0.11.1/src/core/security/json_token.h0000644000175000017500000001064312600663151020633 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H #define GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H #include #include #include "src/core/json/json.h" /* --- Constants. --- */ #define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" #define GRPC_AUTH_JSON_TYPE_INVALID "invalid" #define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account" #define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user" /* --- auth_json_key parsing. --- */ typedef struct { const char *type; char *private_key_id; char *client_id; char *client_email; RSA *private_key; } grpc_auth_json_key; /* Returns 1 if the object is valid, 0 otherwise. */ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key); /* Creates a json_key object from string. Returns an invalid object if a parsing error has been encountered. */ grpc_auth_json_key grpc_auth_json_key_create_from_string( const char *json_string); /* Creates a json_key object from parsed json. Returns an invalid object if a parsing error has been encountered. */ grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json); /* Destructs the object. */ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key); /* --- json token encoding and signing. --- */ /* Caller is responsible for calling gpr_free on the returned value. May return NULL on invalid input. The scope parameter may be NULL. */ char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope); /* Override encode_and_sign function for testing. */ typedef char *(*grpc_jwt_encode_and_sign_override)( const grpc_auth_json_key *json_key, const char *audience, gpr_timespec token_lifetime, const char *scope); /* Set a custom encode_and_sign override for testing. */ void grpc_jwt_encode_and_sign_set_override( grpc_jwt_encode_and_sign_override func); /* --- auth_refresh_token parsing. --- */ typedef struct { const char *type; char *client_id; char *client_secret; char *refresh_token; } grpc_auth_refresh_token; /* Returns 1 if the object is valid, 0 otherwise. */ int grpc_auth_refresh_token_is_valid( const grpc_auth_refresh_token *refresh_token); /* Creates a refresh token object from string. Returns an invalid object if a parsing error has been encountered. */ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( const char *json_string); /* Creates a refresh token object from parsed json. Returns an invalid object if a parsing error has been encountered. */ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( const grpc_json *json); /* Destructs the object. */ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token); #endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */ grpc-0.11.1/src/core/security/security_context.h0000644000175000017500000001033112600663151022067 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H #define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H #include "src/core/iomgr/pollset.h" #include "src/core/security/credentials.h" /* --- grpc_auth_context --- High level authentication context object. Can optionally be chained. */ /* Property names are always NULL terminated. */ typedef struct { grpc_auth_property *array; size_t count; size_t capacity; } grpc_auth_property_array; struct grpc_auth_context { struct grpc_auth_context *chained; grpc_auth_property_array properties; gpr_refcount refcount; const char *peer_identity_property_name; grpc_pollset *pollset; }; /* Creation. */ grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); /* Refcounting. */ #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG #define GRPC_AUTH_CONTEXT_REF(p, r) \ grpc_auth_context_ref((p), __FILE__, __LINE__, (r)) #define GRPC_AUTH_CONTEXT_UNREF(p, r) \ grpc_auth_context_unref((p), __FILE__, __LINE__, (r)) grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy, const char *file, int line, const char *reason); void grpc_auth_context_unref(grpc_auth_context *policy, const char *file, int line, const char *reason); #else #define GRPC_AUTH_CONTEXT_REF(p, r) grpc_auth_context_ref((p)) #define GRPC_AUTH_CONTEXT_UNREF(p, r) grpc_auth_context_unref((p)) grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); void grpc_auth_context_unref(grpc_auth_context *policy); #endif void grpc_auth_property_reset(grpc_auth_property *property); /* --- grpc_client_security_context --- Internal client-side security context. */ typedef struct { grpc_credentials *creds; grpc_auth_context *auth_context; } grpc_client_security_context; grpc_client_security_context *grpc_client_security_context_create(void); void grpc_client_security_context_destroy(void *ctx); /* --- grpc_server_security_context --- Internal server-side security context. */ typedef struct { grpc_auth_context *auth_context; } grpc_server_security_context; grpc_server_security_context *grpc_server_security_context_create(void); void grpc_server_security_context_destroy(void *ctx); /* --- Auth metadata processing. --- */ #define GRPC_AUTH_METADATA_PROCESSOR_ARG "grpc.auth_metadata_processor" grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p); grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( const grpc_arg *arg); grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( const grpc_channel_args *args); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ grpc-0.11.1/src/core/security/secure_transport_setup.h0000644000175000017500000000456112600663151023306 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H #define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H #include "src/core/iomgr/endpoint.h" #include "src/core/security/security_connector.h" /* --- Secure transport setup --- */ /* Ownership of the secure_endpoint is transfered. */ typedef void (*grpc_secure_transport_setup_done_cb)( void *user_data, grpc_security_status status, grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint); /* Calls the callback upon completion. */ void grpc_setup_secure_transport(grpc_security_connector *connector, grpc_endpoint *nonsecure_endpoint, grpc_secure_transport_setup_done_cb cb, void *user_data); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H */ grpc-0.11.1/src/core/security/auth_filters.h0000644000175000017500000000354312600663151021154 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H #define GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H #include "src/core/channel/channel_stack.h" extern const grpc_channel_filter grpc_client_auth_filter; extern const grpc_channel_filter grpc_server_auth_filter; #endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */ grpc-0.11.1/src/core/security/jwt_verifier.h0000644000175000017500000001310412600663151021154 0ustar apollockapollock/* * * 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 disclaimser. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimser * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H #define GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H #include "src/core/iomgr/pollset.h" #include "src/core/json/json.h" #include #include /* --- Constants. --- */ #define GRPC_OPENID_CONFIG_URL_SUFFIX "/.well-known/openid-configuration" #define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN \ "developer.gserviceaccount.com" #define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \ "www.googleapis.com/robot/v1/metadata/x509" /* --- grpc_jwt_verifier_status. --- */ typedef enum { GRPC_JWT_VERIFIER_OK = 0, GRPC_JWT_VERIFIER_BAD_SIGNATURE, GRPC_JWT_VERIFIER_BAD_FORMAT, GRPC_JWT_VERIFIER_BAD_AUDIENCE, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE, GRPC_JWT_VERIFIER_GENERIC_ERROR } grpc_jwt_verifier_status; const char *grpc_jwt_verifier_status_to_string(grpc_jwt_verifier_status status); /* --- grpc_jwt_claims. --- */ typedef struct grpc_jwt_claims grpc_jwt_claims; void grpc_jwt_claims_destroy(grpc_jwt_claims *claims); /* Returns the whole JSON tree of the claims. */ const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims); /* Access to registered claims in https://tools.ietf.org/html/rfc7519#page-9 */ const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims); const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims); const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims); const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims); gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims); gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims); gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims); /* --- grpc_jwt_verifier. --- */ typedef struct grpc_jwt_verifier grpc_jwt_verifier; typedef struct { /* The email domain is the part after the @ sign. */ const char *email_domain; /* The key url prefix will be used to get the public key from the issuer: https:/// Therefore the key_url_prefix must NOT contain https://. */ const char *key_url_prefix; } grpc_jwt_verifier_email_domain_key_url_mapping; /* Globals to control the verifier. Not thread-safe. */ extern gpr_timespec grpc_jwt_verifier_clock_skew; extern gpr_timespec grpc_jwt_verifier_max_delay; /* The verifier can be created with some custom mappings to help with key discovery in the case where the issuer is an email address. mappings can be NULL in which case num_mappings MUST be 0. A verifier object has one built-in mapping (unless overridden): GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN -> GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX.*/ grpc_jwt_verifier *grpc_jwt_verifier_create( const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, size_t num_mappings); /*The verifier must not be destroyed if there are still outstanding callbacks.*/ void grpc_jwt_verifier_destroy(grpc_jwt_verifier *verifier); /* User provided callback that will be called when the verification of the JWT is done (maybe in another thread). It is the responsibility of the callee to call grpc_jwt_claims_destroy on the claims. */ typedef void (*grpc_jwt_verification_done_cb)(void *user_data, grpc_jwt_verifier_status status, grpc_jwt_claims *claims); /* Verifies for the JWT for the given expected audience. */ void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier, grpc_pollset *pollset, const char *jwt, const char *audience, grpc_jwt_verification_done_cb cb, void *user_data); /* --- TESTING ONLY exposed functions. --- */ grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer); grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, const char *audience); #endif /* GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H */ grpc-0.11.1/src/core/security/credentials_metadata.c0000644000175000017500000000736312600663151022617 0ustar apollockapollock/* * * 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/security/credentials.h" #include #include static void store_ensure_capacity(grpc_credentials_md_store *store) { if (store->num_entries == store->allocated) { store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2; store->entries = gpr_realloc( store->entries, store->allocated * sizeof(grpc_credentials_md)); } } grpc_credentials_md_store *grpc_credentials_md_store_create( size_t initial_capacity) { grpc_credentials_md_store *store = gpr_malloc(sizeof(grpc_credentials_md_store)); memset(store, 0, sizeof(grpc_credentials_md_store)); if (initial_capacity > 0) { store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); store->allocated = initial_capacity; } gpr_ref_init(&store->refcount, 1); return store; } void grpc_credentials_md_store_add(grpc_credentials_md_store *store, gpr_slice key, gpr_slice value) { if (store == NULL) return; store_ensure_capacity(store); store->entries[store->num_entries].key = gpr_slice_ref(key); store->entries[store->num_entries].value = gpr_slice_ref(value); store->num_entries++; } void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, const char *key, const char *value) { if (store == NULL) return; store_ensure_capacity(store); store->entries[store->num_entries].key = gpr_slice_from_copied_string(key); store->entries[store->num_entries].value = gpr_slice_from_copied_string(value); store->num_entries++; } grpc_credentials_md_store *grpc_credentials_md_store_ref( grpc_credentials_md_store *store) { if (store == NULL) return NULL; gpr_ref(&store->refcount); return store; } void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { if (store == NULL) return; if (gpr_unref(&store->refcount)) { if (store->entries != NULL) { size_t i; for (i = 0; i < store->num_entries; i++) { gpr_slice_unref(store->entries[i].key); gpr_slice_unref(store->entries[i].value); } gpr_free(store->entries); } gpr_free(store); } } grpc-0.11.1/src/core/security/jwt_verifier.c0000644000175000017500000006512212600663151021156 0ustar apollockapollock/* * * 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 disclaimser. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimser * 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/security/jwt_verifier.h" #include #include "src/core/httpcli/httpcli.h" #include "src/core/security/base64.h" #include #include #include #include #include /* --- Utils. --- */ const char *grpc_jwt_verifier_status_to_string( grpc_jwt_verifier_status status) { switch (status) { case GRPC_JWT_VERIFIER_OK: return "OK"; case GRPC_JWT_VERIFIER_BAD_SIGNATURE: return "BAD_SIGNATURE"; case GRPC_JWT_VERIFIER_BAD_FORMAT: return "BAD_FORMAT"; case GRPC_JWT_VERIFIER_BAD_AUDIENCE: return "BAD_AUDIENCE"; case GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR: return "KEY_RETRIEVAL_ERROR"; case GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE: return "TIME_CONSTRAINT_FAILURE"; case GRPC_JWT_VERIFIER_GENERIC_ERROR: return "GENERIC_ERROR"; default: return "UNKNOWN"; } } static const EVP_MD *evp_md_from_alg(const char *alg) { if (strcmp(alg, "RS256") == 0) { return EVP_sha256(); } else if (strcmp(alg, "RS384") == 0) { return EVP_sha384(); } else if (strcmp(alg, "RS512") == 0) { return EVP_sha512(); } else { return NULL; } } static grpc_json *parse_json_part_from_jwt(const char *str, size_t len, gpr_slice *buffer) { grpc_json *json; *buffer = grpc_base64_decode_with_len(str, len, 1); if (GPR_SLICE_IS_EMPTY(*buffer)) { gpr_log(GPR_ERROR, "Invalid base64."); return NULL; } json = grpc_json_parse_string_with_len((char *)GPR_SLICE_START_PTR(*buffer), GPR_SLICE_LENGTH(*buffer)); if (json == NULL) { gpr_slice_unref(*buffer); gpr_log(GPR_ERROR, "JSON parsing error."); } return json; } static const char *validate_string_field(const grpc_json *json, const char *key) { if (json->type != GRPC_JSON_STRING) { gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value); return NULL; } return json->value; } static gpr_timespec validate_time_field(const grpc_json *json, const char *key) { gpr_timespec result = gpr_time_0(GPR_CLOCK_REALTIME); if (json->type != GRPC_JSON_NUMBER) { gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value); return result; } result.tv_sec = strtol(json->value, NULL, 10); return result; } /* --- JOSE header. see http://tools.ietf.org/html/rfc7515#section-4 --- */ typedef struct { const char *alg; const char *kid; const char *typ; /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */ gpr_slice buffer; } jose_header; static void jose_header_destroy(jose_header *h) { gpr_slice_unref(h->buffer); gpr_free(h); } /* Takes ownership of json and buffer. */ static jose_header *jose_header_from_json(grpc_json *json, gpr_slice buffer) { grpc_json *cur; jose_header *h = gpr_malloc(sizeof(jose_header)); memset(h, 0, sizeof(jose_header)); h->buffer = buffer; for (cur = json->child; cur != NULL; cur = cur->next) { if (strcmp(cur->key, "alg") == 0) { /* We only support RSA-1.5 signatures for now. Beware of this if we add HMAC support: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ */ if (cur->type != GRPC_JSON_STRING || strncmp(cur->value, "RS", 2) || evp_md_from_alg(cur->value) == NULL) { gpr_log(GPR_ERROR, "Invalid alg field [%s]", cur->value); goto error; } h->alg = cur->value; } else if (strcmp(cur->key, "typ") == 0) { h->typ = validate_string_field(cur, "typ"); if (h->typ == NULL) goto error; } else if (strcmp(cur->key, "kid") == 0) { h->kid = validate_string_field(cur, "kid"); if (h->kid == NULL) goto error; } } if (h->alg == NULL) { gpr_log(GPR_ERROR, "Missing alg field."); goto error; } grpc_json_destroy(json); h->buffer = buffer; return h; error: grpc_json_destroy(json); jose_header_destroy(h); return NULL; } /* --- JWT claims. see http://tools.ietf.org/html/rfc7519#section-4.1 */ struct grpc_jwt_claims { /* Well known properties already parsed. */ const char *sub; const char *iss; const char *aud; const char *jti; gpr_timespec iat; gpr_timespec exp; gpr_timespec nbf; grpc_json *json; gpr_slice buffer; }; void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) { grpc_json_destroy(claims->json); gpr_slice_unref(claims->buffer); gpr_free(claims); } const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims) { if (claims == NULL) return NULL; return claims->json; } const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims) { if (claims == NULL) return NULL; return claims->sub; } const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims) { if (claims == NULL) return NULL; return claims->iss; } const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims) { if (claims == NULL) return NULL; return claims->jti; } const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims) { if (claims == NULL) return NULL; return claims->aud; } gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims) { if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME); return claims->iat; } gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims) { if (claims == NULL) return gpr_inf_future(GPR_CLOCK_REALTIME); return claims->exp; } gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) { if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME); return claims->nbf; } /* Takes ownership of json and buffer even in case of failure. */ grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) { grpc_json *cur; grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims)); memset(claims, 0, sizeof(grpc_jwt_claims)); claims->json = json; claims->buffer = buffer; claims->iat = gpr_inf_past(GPR_CLOCK_REALTIME); claims->nbf = gpr_inf_past(GPR_CLOCK_REALTIME); claims->exp = gpr_inf_future(GPR_CLOCK_REALTIME); /* Per the spec, all fields are optional. */ for (cur = json->child; cur != NULL; cur = cur->next) { if (strcmp(cur->key, "sub") == 0) { claims->sub = validate_string_field(cur, "sub"); if (claims->sub == NULL) goto error; } else if (strcmp(cur->key, "iss") == 0) { claims->iss = validate_string_field(cur, "iss"); if (claims->iss == NULL) goto error; } else if (strcmp(cur->key, "aud") == 0) { claims->aud = validate_string_field(cur, "aud"); if (claims->aud == NULL) goto error; } else if (strcmp(cur->key, "jti") == 0) { claims->jti = validate_string_field(cur, "jti"); if (claims->jti == NULL) goto error; } else if (strcmp(cur->key, "iat") == 0) { claims->iat = validate_time_field(cur, "iat"); if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) goto error; } else if (strcmp(cur->key, "exp") == 0) { claims->exp = validate_time_field(cur, "exp"); if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) goto error; } else if (strcmp(cur->key, "nbf") == 0) { claims->nbf = validate_time_field(cur, "nbf"); if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) goto error; } } return claims; error: grpc_jwt_claims_destroy(claims); return NULL; } grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, const char *audience) { gpr_timespec skewed_now; int audience_ok; GPR_ASSERT(claims != NULL); skewed_now = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew); if (gpr_time_cmp(skewed_now, claims->nbf) < 0) { gpr_log(GPR_ERROR, "JWT is not valid yet."); return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; } skewed_now = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew); if (gpr_time_cmp(skewed_now, claims->exp) > 0) { gpr_log(GPR_ERROR, "JWT is expired."); return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; } if (audience == NULL) { audience_ok = claims->aud == NULL; } else { audience_ok = claims->aud != NULL && strcmp(audience, claims->aud) == 0; } if (!audience_ok) { gpr_log(GPR_ERROR, "Audience mismatch: expected %s and found %s.", audience == NULL ? "NULL" : audience, claims->aud == NULL ? "NULL" : claims->aud); return GRPC_JWT_VERIFIER_BAD_AUDIENCE; } return GRPC_JWT_VERIFIER_OK; } /* --- verifier_cb_ctx object. --- */ typedef struct { grpc_jwt_verifier *verifier; grpc_pollset *pollset; jose_header *header; grpc_jwt_claims *claims; char *audience; gpr_slice signature; gpr_slice signed_data; void *user_data; grpc_jwt_verification_done_cb user_cb; } verifier_cb_ctx; /* Takes ownership of the header, claims and signature. */ static verifier_cb_ctx *verifier_cb_ctx_create( grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header, grpc_jwt_claims *claims, const char *audience, gpr_slice signature, const char *signed_jwt, size_t signed_jwt_len, void *user_data, grpc_jwt_verification_done_cb cb) { verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx)); memset(ctx, 0, sizeof(verifier_cb_ctx)); ctx->verifier = verifier; ctx->pollset = pollset; ctx->header = header; ctx->audience = gpr_strdup(audience); ctx->claims = claims; ctx->signature = signature; ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len); ctx->user_data = user_data; ctx->user_cb = cb; return ctx; } void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { if (ctx->audience != NULL) gpr_free(ctx->audience); if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); gpr_slice_unref(ctx->signature); gpr_slice_unref(ctx->signed_data); jose_header_destroy(ctx->header); /* TODO: see what to do with claims... */ gpr_free(ctx); } /* --- grpc_jwt_verifier object. --- */ /* Clock skew defaults to one minute. */ gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN}; /* Max delay defaults to one minute. */ gpr_timespec grpc_jwt_verifier_max_delay = {60, 0, GPR_TIMESPAN}; typedef struct { char *email_domain; char *key_url_prefix; } email_key_mapping; struct grpc_jwt_verifier { email_key_mapping *mappings; size_t num_mappings; /* Should be very few, linear search ok. */ size_t allocated_mappings; grpc_httpcli_context http_ctx; }; static grpc_json *json_from_http(const grpc_httpcli_response *response) { grpc_json *json = NULL; if (response == NULL) { gpr_log(GPR_ERROR, "HTTP response is NULL."); return NULL; } if (response->status != 200) { gpr_log(GPR_ERROR, "Call to http server failed with error %d.", response->status); return NULL; } json = grpc_json_parse_string_with_len(response->body, response->body_length); if (json == NULL) { gpr_log(GPR_ERROR, "Invalid JSON found in response."); } return json; } static const grpc_json *find_property_by_name(const grpc_json *json, const char *name) { const grpc_json *cur; for (cur = json->child; cur != NULL; cur = cur->next) { if (strcmp(cur->key, name) == 0) return cur; } return NULL; } static EVP_PKEY *extract_pkey_from_x509(const char *x509_str) { X509 *x509 = NULL; EVP_PKEY *result = NULL; BIO *bio = BIO_new(BIO_s_mem()); BIO_write(bio, x509_str, strlen(x509_str)); x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); if (x509 == NULL) { gpr_log(GPR_ERROR, "Unable to parse x509 cert."); goto end; } result = X509_get_pubkey(x509); if (result == NULL) { gpr_log(GPR_ERROR, "Cannot find public key in X509 cert."); } end: BIO_free(bio); if (x509 != NULL) X509_free(x509); return result; } static BIGNUM *bignum_from_base64(const char *b64) { BIGNUM *result = NULL; gpr_slice bin; if (b64 == NULL) return NULL; bin = grpc_base64_decode(b64, 1); if (GPR_SLICE_IS_EMPTY(bin)) { gpr_log(GPR_ERROR, "Invalid base64 for big num."); return NULL; } result = BN_bin2bn(GPR_SLICE_START_PTR(bin), GPR_SLICE_LENGTH(bin), NULL); gpr_slice_unref(bin); return result; } static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) { const grpc_json *key_prop; RSA *rsa = NULL; EVP_PKEY *result = NULL; GPR_ASSERT(kty != NULL && json != NULL); if (strcmp(kty, "RSA") != 0) { gpr_log(GPR_ERROR, "Unsupported key type %s.", kty); goto end; } rsa = RSA_new(); if (rsa == NULL) { gpr_log(GPR_ERROR, "Could not create rsa key."); goto end; } for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) { if (strcmp(key_prop->key, "n") == 0) { rsa->n = bignum_from_base64(validate_string_field(key_prop, "n")); if (rsa->n == NULL) goto end; } else if (strcmp(key_prop->key, "e") == 0) { rsa->e = bignum_from_base64(validate_string_field(key_prop, "e")); if (rsa->e == NULL) goto end; } } if (rsa->e == NULL || rsa->n == NULL) { gpr_log(GPR_ERROR, "Missing RSA public key field."); goto end; } result = EVP_PKEY_new(); EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */ end: if (rsa != NULL) RSA_free(rsa); return result; } static EVP_PKEY *find_verification_key(const grpc_json *json, const char *header_alg, const char *header_kid) { const grpc_json *jkey; const grpc_json *jwk_keys; /* Try to parse the json as a JWK set: https://tools.ietf.org/html/rfc7517#section-5. */ jwk_keys = find_property_by_name(json, "keys"); if (jwk_keys == NULL) { /* Use the google proprietary format which is: { : , : , ... } */ const grpc_json *cur = find_property_by_name(json, header_kid); if (cur == NULL) return NULL; return extract_pkey_from_x509(cur->value); } if (jwk_keys->type != GRPC_JSON_ARRAY) { gpr_log(GPR_ERROR, "Unexpected value type of keys property in jwks key set."); return NULL; } /* Key format is specified in: https://tools.ietf.org/html/rfc7518#section-6. */ for (jkey = jwk_keys->child; jkey != NULL; jkey = jkey->next) { grpc_json *key_prop; const char *alg = NULL; const char *kid = NULL; const char *kty = NULL; if (jkey->type != GRPC_JSON_OBJECT) continue; for (key_prop = jkey->child; key_prop != NULL; key_prop = key_prop->next) { if (strcmp(key_prop->key, "alg") == 0 && key_prop->type == GRPC_JSON_STRING) { alg = key_prop->value; } else if (strcmp(key_prop->key, "kid") == 0 && key_prop->type == GRPC_JSON_STRING) { kid = key_prop->value; } else if (strcmp(key_prop->key, "kty") == 0 && key_prop->type == GRPC_JSON_STRING) { kty = key_prop->value; } } if (alg != NULL && kid != NULL && kty != NULL && strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) { return pkey_from_jwk(jkey, kty); } } gpr_log(GPR_ERROR, "Could not find matching key in key set for kid=%s and alg=%s", header_kid, header_alg); return NULL; } static int verify_jwt_signature(EVP_PKEY *key, const char *alg, gpr_slice signature, gpr_slice signed_data) { EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); const EVP_MD *md = evp_md_from_alg(alg); int result = 0; GPR_ASSERT(md != NULL); /* Checked before. */ if (md_ctx == NULL) { gpr_log(GPR_ERROR, "Could not create EVP_MD_CTX."); goto end; } if (EVP_DigestVerifyInit(md_ctx, NULL, md, NULL, key) != 1) { gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed."); goto end; } if (EVP_DigestVerifyUpdate(md_ctx, GPR_SLICE_START_PTR(signed_data), GPR_SLICE_LENGTH(signed_data)) != 1) { gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed."); goto end; } if (EVP_DigestVerifyFinal(md_ctx, GPR_SLICE_START_PTR(signature), GPR_SLICE_LENGTH(signature)) != 1) { gpr_log(GPR_ERROR, "JWT signature verification failed."); goto end; } result = 1; end: if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); return result; } static void on_keys_retrieved(void *user_data, const grpc_httpcli_response *response) { grpc_json *json = json_from_http(response); verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data; EVP_PKEY *verification_key = NULL; grpc_jwt_verifier_status status = GRPC_JWT_VERIFIER_GENERIC_ERROR; grpc_jwt_claims *claims = NULL; if (json == NULL) { status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR; goto end; } verification_key = find_verification_key(json, ctx->header->alg, ctx->header->kid); if (verification_key == NULL) { gpr_log(GPR_ERROR, "Could not find verification key with kid %s.", ctx->header->kid); status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR; goto end; } if (!verify_jwt_signature(verification_key, ctx->header->alg, ctx->signature, ctx->signed_data)) { status = GRPC_JWT_VERIFIER_BAD_SIGNATURE; goto end; } status = grpc_jwt_claims_check(ctx->claims, ctx->audience); if (status == GRPC_JWT_VERIFIER_OK) { /* Pass ownership. */ claims = ctx->claims; ctx->claims = NULL; } end: if (json != NULL) grpc_json_destroy(json); if (verification_key != NULL) EVP_PKEY_free(verification_key); ctx->user_cb(ctx->user_data, status, claims); verifier_cb_ctx_destroy(ctx); } static void on_openid_config_retrieved(void *user_data, const grpc_httpcli_response *response) { const grpc_json *cur; grpc_json *json = json_from_http(response); verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data; grpc_httpcli_request req; const char *jwks_uri; /* TODO(jboeuf): Cache the jwks_uri in order to avoid this hop next time.*/ if (json == NULL) goto error; cur = find_property_by_name(json, "jwks_uri"); if (cur == NULL) { gpr_log(GPR_ERROR, "Could not find jwks_uri in openid config."); goto error; } jwks_uri = validate_string_field(cur, "jwks_uri"); if (jwks_uri == NULL) goto error; if (strstr(jwks_uri, "https://") != jwks_uri) { gpr_log(GPR_ERROR, "Invalid non https jwks_uri: %s.", jwks_uri); goto error; } jwks_uri += 8; req.handshaker = &grpc_httpcli_ssl; req.host = gpr_strdup(jwks_uri); req.path = strchr(jwks_uri, '/'); if (req.path == NULL) { req.path = ""; } else { *(req.host + (req.path - jwks_uri)) = '\0'; } grpc_httpcli_get( &ctx->verifier->http_ctx, ctx->pollset, &req, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), on_keys_retrieved, ctx); grpc_json_destroy(json); gpr_free(req.host); return; error: if (json != NULL) grpc_json_destroy(json); ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); verifier_cb_ctx_destroy(ctx); } static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v, const char *email_domain) { size_t i; if (v->mappings == NULL) return NULL; for (i = 0; i < v->num_mappings; i++) { if (strcmp(email_domain, v->mappings[i].email_domain) == 0) { return &v->mappings[i]; } } return NULL; } static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain, const char *key_url_prefix) { email_key_mapping *mapping = verifier_get_mapping(v, email_domain); GPR_ASSERT(v->num_mappings < v->allocated_mappings); if (mapping != NULL) { gpr_free(mapping->key_url_prefix); mapping->key_url_prefix = gpr_strdup(key_url_prefix); return; } v->mappings[v->num_mappings].email_domain = gpr_strdup(email_domain); v->mappings[v->num_mappings].key_url_prefix = gpr_strdup(key_url_prefix); v->num_mappings++; GPR_ASSERT(v->num_mappings <= v->allocated_mappings); } /* Takes ownership of ctx. */ static void retrieve_key_and_verify(verifier_cb_ctx *ctx) { const char *at_sign; grpc_httpcli_response_cb http_cb; char *path_prefix = NULL; const char *iss; grpc_httpcli_request req; memset(&req, 0, sizeof(grpc_httpcli_request)); req.handshaker = &grpc_httpcli_ssl; GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL); iss = ctx->claims->iss; if (ctx->header->kid == NULL) { gpr_log(GPR_ERROR, "Missing kid in jose header."); goto error; } if (iss == NULL) { gpr_log(GPR_ERROR, "Missing iss in claims."); goto error; } /* This code relies on: https://openid.net/specs/openid-connect-discovery-1_0.html Nobody seems to implement the account/email/webfinger part 2. of the spec so we will rely instead on email/url mappings if we detect such an issuer. Part 4, on the other hand is implemented by both google and salesforce. */ /* Very non-sophisticated way to detect an email address. Should be good enough for now... */ at_sign = strchr(iss, '@'); if (at_sign != NULL) { email_key_mapping *mapping; const char *email_domain = at_sign + 1; GPR_ASSERT(ctx->verifier != NULL); mapping = verifier_get_mapping(ctx->verifier, email_domain); if (mapping == NULL) { gpr_log(GPR_ERROR, "Missing mapping for issuer email."); goto error; } req.host = gpr_strdup(mapping->key_url_prefix); path_prefix = strchr(req.host, '/'); if (path_prefix == NULL) { gpr_asprintf(&req.path, "/%s", iss); } else { *(path_prefix++) = '\0'; gpr_asprintf(&req.path, "/%s/%s", path_prefix, iss); } http_cb = on_keys_retrieved; } else { req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); path_prefix = strchr(req.host, '/'); if (path_prefix == NULL) { req.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); } else { *(path_prefix++) = 0; gpr_asprintf(&req.path, "/%s%s", path_prefix, GRPC_OPENID_CONFIG_URL_SUFFIX); } http_cb = on_openid_config_retrieved; } grpc_httpcli_get( &ctx->verifier->http_ctx, ctx->pollset, &req, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), http_cb, ctx); gpr_free(req.host); gpr_free(req.path); return; error: ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); verifier_cb_ctx_destroy(ctx); } void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier, grpc_pollset *pollset, const char *jwt, const char *audience, grpc_jwt_verification_done_cb cb, void *user_data) { const char *dot = NULL; grpc_json *json; jose_header *header = NULL; grpc_jwt_claims *claims = NULL; gpr_slice header_buffer; gpr_slice claims_buffer; gpr_slice signature; size_t signed_jwt_len; const char *cur = jwt; GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL); dot = strchr(cur, '.'); if (dot == NULL) goto error; json = parse_json_part_from_jwt(cur, dot - cur, &header_buffer); if (json == NULL) goto error; header = jose_header_from_json(json, header_buffer); if (header == NULL) goto error; cur = dot + 1; dot = strchr(cur, '.'); if (dot == NULL) goto error; json = parse_json_part_from_jwt(cur, dot - cur, &claims_buffer); if (json == NULL) goto error; claims = grpc_jwt_claims_from_json(json, claims_buffer); if (claims == NULL) goto error; signed_jwt_len = (size_t)(dot - jwt); cur = dot + 1; signature = grpc_base64_decode(cur, 1); if (GPR_SLICE_IS_EMPTY(signature)) goto error; retrieve_key_and_verify( verifier_cb_ctx_create(verifier, pollset, header, claims, audience, signature, jwt, signed_jwt_len, user_data, cb)); return; error: if (header != NULL) jose_header_destroy(header); if (claims != NULL) grpc_jwt_claims_destroy(claims); cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL); } grpc_jwt_verifier *grpc_jwt_verifier_create( const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, size_t num_mappings) { grpc_jwt_verifier *v = gpr_malloc(sizeof(grpc_jwt_verifier)); memset(v, 0, sizeof(grpc_jwt_verifier)); grpc_httpcli_context_init(&v->http_ctx); /* We know at least of one mapping. */ v->allocated_mappings = 1 + num_mappings; v->mappings = gpr_malloc(v->allocated_mappings * sizeof(email_key_mapping)); verifier_put_mapping(v, GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN, GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX); /* User-Provided mappings. */ if (mappings != NULL) { size_t i; for (i = 0; i < num_mappings; i++) { verifier_put_mapping(v, mappings[i].email_domain, mappings[i].key_url_prefix); } } return v; } void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v) { size_t i; if (v == NULL) return; grpc_httpcli_context_destroy(&v->http_ctx); if (v->mappings != NULL) { for (i = 0; i < v->num_mappings; i++) { gpr_free(v->mappings[i].email_domain); gpr_free(v->mappings[i].key_url_prefix); } gpr_free(v->mappings); } gpr_free(v); } grpc-0.11.1/src/core/security/server_auth_filter.c0000644000175000017500000002477412600663151022363 0ustar apollockapollock/* * * 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 #include "src/core/security/auth_filters.h" #include "src/core/security/security_connector.h" #include "src/core/security/security_context.h" #include #include typedef struct call_data { gpr_uint8 got_client_metadata; grpc_stream_op_buffer *recv_ops; /* Closure to call when finished with the auth_on_recv hook. */ grpc_iomgr_closure *on_done_recv; /* Receive closures are chained: we inject this closure as the on_done_recv up-call on transport_op, and remember to call our on_done_recv member after handling it. */ grpc_iomgr_closure auth_on_recv; grpc_transport_stream_op transport_op; grpc_metadata_array md; const grpc_metadata *consumed_md; size_t num_consumed_md; grpc_stream_op *md_op; grpc_auth_context *auth_context; } call_data; typedef struct channel_data { grpc_security_connector *security_connector; grpc_auth_metadata_processor processor; grpc_mdctx *mdctx; } channel_data; static grpc_metadata_array metadata_batch_to_md_array( const grpc_metadata_batch *batch) { grpc_linked_mdelem *l; grpc_metadata_array result; grpc_metadata_array_init(&result); for (l = batch->list.head; l != NULL; l = l->next) { grpc_metadata *usr_md = NULL; grpc_mdelem *md = l->md; grpc_mdstr *key = md->key; grpc_mdstr *value = md->value; if (result.count == result.capacity) { result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2); result.metadata = gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata)); } usr_md = &result.metadata[result.count++]; usr_md->key = grpc_mdstr_as_c_string(key); usr_md->value = grpc_mdstr_as_c_string(value); usr_md->value_length = GPR_SLICE_LENGTH(value->slice); } return result; } static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; size_t i; for (i = 0; i < calld->num_consumed_md; i++) { const grpc_metadata *consumed_md = &calld->consumed_md[i]; /* Maybe we could do a pointer comparison but we do not have any guarantee that the metadata processor used the same pointers for consumed_md in the callback. */ if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) || GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) { continue; } if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key, GPR_SLICE_LENGTH(md->key->slice)) == 0 && memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value, GPR_SLICE_LENGTH(md->value->slice)) == 0) { return NULL; /* Delete. */ } } return md; } static void on_md_processing_done( void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, const grpc_metadata *response_md, size_t num_response_md, grpc_status_code status, const char *error_details) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; /* TODO(jboeuf): Implement support for response_md. */ if (response_md != NULL && num_response_md > 0) { gpr_log(GPR_INFO, "response_md in auth metadata processing not supported for now. " "Ignoring..."); } if (status == GRPC_STATUS_OK) { calld->consumed_md = consumed_md; calld->num_consumed_md = num_consumed_md; grpc_metadata_batch_filter(&calld->md_op->data.metadata, remove_consumed_md, elem); grpc_metadata_array_destroy(&calld->md); calld->on_done_recv->cb(calld->on_done_recv->cb_arg, 1); } else { gpr_slice message; grpc_metadata_array_destroy(&calld->md); error_details = error_details != NULL ? error_details : "Authentication metadata processing failed."; message = gpr_slice_from_copied_string(error_details); grpc_sopb_reset(calld->recv_ops); grpc_transport_stream_op_add_close(&calld->transport_op, status, &message); grpc_call_next_op(elem, &calld->transport_op); } } static void auth_on_recv(void *user_data, int success) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; if (success) { size_t i; size_t nops = calld->recv_ops->nops; grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue; calld->got_client_metadata = 1; if (chand->processor.process == NULL) continue; calld->md_op = op; calld->md = metadata_batch_to_md_array(&op->data.metadata); chand->processor.process(chand->processor.state, calld->auth_context, calld->md.metadata, calld->md.count, on_md_processing_done, elem); return; } } calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); } static void set_recv_ops_md_callbacks(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; if (op->recv_ops && !calld->got_client_metadata) { /* substitute our callback for the higher callback */ calld->recv_ops = op->recv_ops; calld->on_done_recv = op->on_done_recv; op->on_done_recv = &calld->auth_on_recv; calld->transport_op = *op; } } /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void auth_start_transport_op(grpc_call_element *elem, grpc_transport_stream_op *op) { set_recv_ops_md_callbacks(elem, op); grpc_call_next_op(elem, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_server_security_context *server_ctx = NULL; /* initialize members */ memset(calld, 0, sizeof(*calld)); grpc_iomgr_closure_init(&calld->auth_on_recv, auth_on_recv, elem); GPR_ASSERT(initial_op && initial_op->context != NULL && initial_op->context[GRPC_CONTEXT_SECURITY].value == NULL); /* Create a security context for the call and reference the auth context from the channel. */ if (initial_op->context[GRPC_CONTEXT_SECURITY].value != NULL) { initial_op->context[GRPC_CONTEXT_SECURITY].destroy( initial_op->context[GRPC_CONTEXT_SECURITY].value); } server_ctx = grpc_server_security_context_create(); server_ctx->auth_context = grpc_auth_context_create(chand->security_connector->auth_context); server_ctx->auth_context->pollset = initial_op->bind_pollset; initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx; initial_op->context[GRPC_CONTEXT_SECURITY].destroy = grpc_server_security_context_destroy; calld->auth_context = server_ctx->auth_context; /* Set the metadata callbacks. */ set_recv_ops_md_callbacks(elem, initial_op); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) {} /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { grpc_security_connector *sc = grpc_find_security_connector_in_args(args); grpc_auth_metadata_processor *processor = grpc_find_auth_metadata_processor_in_args(args); /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; /* The first and the last filters tend to be implemented differently to handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!is_first); GPR_ASSERT(!is_last); GPR_ASSERT(sc != NULL); GPR_ASSERT(processor != NULL); /* initialize members */ GPR_ASSERT(!sc->is_client_side); chand->security_connector = GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter"); chand->mdctx = mdctx; chand->processor = *processor; } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector, "server_auth_filter"); } const grpc_channel_filter grpc_server_auth_filter = { auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "server-auth"}; grpc-0.11.1/src/core/security/credentials.h0000644000175000017500000002732412600663151020763 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H #define GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H #include "src/core/transport/stream_op.h" #include #include #include #include "src/core/httpcli/httpcli.h" #include "src/core/security/json_token.h" #include "src/core/security/security_connector.h" struct grpc_httpcli_response; /* --- Constants. --- */ typedef enum { GRPC_CREDENTIALS_OK = 0, GRPC_CREDENTIALS_ERROR } grpc_credentials_status; #define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" #define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" #define GRPC_CREDENTIALS_TYPE_JWT "Jwt" #define GRPC_CREDENTIALS_TYPE_IAM "Iam" #define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" #define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity" #define GRPC_AUTHORIZATION_METADATA_KEY "Authorization" #define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \ "x-goog-iam-authorization-token" #define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector" #define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud" #define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \ "application_default_credentials.json" #define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60 #define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ "/computeMetadata/v1/instance/service-accounts/default/token" #define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com" #define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token" #define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \ "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \ "assertion=" #define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \ "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token" /* --- grpc_credentials_md. --- */ typedef struct { gpr_slice key; gpr_slice value; } grpc_credentials_md; typedef struct { grpc_credentials_md *entries; size_t num_entries; size_t allocated; gpr_refcount refcount; } grpc_credentials_md_store; grpc_credentials_md_store *grpc_credentials_md_store_create( size_t initial_capacity); /* Will ref key and value. */ void grpc_credentials_md_store_add(grpc_credentials_md_store *store, gpr_slice key, gpr_slice value); void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, const char *key, const char *value); grpc_credentials_md_store *grpc_credentials_md_store_ref( grpc_credentials_md_store *store); void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); /* --- grpc_credentials. --- */ /* Creates a fake transport security credentials object for testing. */ grpc_credentials *grpc_fake_transport_security_credentials_create(void); /* Creates a fake server transport security credentials object for testing. */ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( void); /* It is the caller's responsibility to gpr_free the result if not NULL. */ char *grpc_get_well_known_google_credentials_file_path(void); typedef void (*grpc_credentials_metadata_cb)(void *user_data, grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status); typedef struct { void (*destruct)(grpc_credentials *c); int (*has_request_metadata)(const grpc_credentials *c); int (*has_request_metadata_only)(const grpc_credentials *c); void (*get_request_metadata)(grpc_credentials *c, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); grpc_security_status (*create_security_connector)( grpc_credentials *c, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args); } grpc_credentials_vtable; struct grpc_credentials { const grpc_credentials_vtable *vtable; const char *type; gpr_refcount refcount; }; grpc_credentials *grpc_credentials_ref(grpc_credentials *creds); void grpc_credentials_unref(grpc_credentials *creds); int grpc_credentials_has_request_metadata(grpc_credentials *creds); int grpc_credentials_has_request_metadata_only(grpc_credentials *creds); void grpc_credentials_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); /* Creates a security connector for the channel. May also create new channel args for the channel to be used in place of the passed in const args if returned non NULL. In that case the caller is responsible for destroying new_args after channel creation. */ grpc_security_status grpc_credentials_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args); typedef struct { grpc_credentials **creds_array; size_t num_creds; } grpc_credentials_array; const grpc_credentials_array *grpc_composite_credentials_get_credentials( grpc_credentials *composite_creds); /* Returns creds if creds is of the specified type or the inner creds of the specified type (if found), if the creds is of type COMPOSITE. If composite_creds is not NULL, *composite_creds will point to creds if of type COMPOSITE in case of success. */ grpc_credentials *grpc_credentials_contains_type( grpc_credentials *creds, const char *type, grpc_credentials **composite_creds); /* Exposed for testing only. */ grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( const struct grpc_httpcli_response *response, grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); void grpc_flush_cached_google_default_credentials(void); /* Metadata-only credentials with the specified key and value where asynchronicity can be simulated for testing. */ grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, const char *md_value, int is_async); /* Private constructor for jwt credentials from an already parsed json key. Takes ownership of the key. */ grpc_credentials * grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime); /* Private constructor for refresh token credentials from an already parsed refresh token. Takes ownership of the refresh token. */ grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token token); /* --- grpc_server_credentials. --- */ typedef struct { void (*destruct)(grpc_server_credentials *c); grpc_security_status (*create_security_connector)( grpc_server_credentials *c, grpc_security_connector **sc); } grpc_server_credentials_vtable; /* TODO(jboeuf): Add a refcount. */ struct grpc_server_credentials { const grpc_server_credentials_vtable *vtable; const char *type; gpr_refcount refcount; grpc_auth_metadata_processor processor; }; grpc_security_status grpc_server_credentials_create_security_connector( grpc_server_credentials *creds, grpc_security_connector **sc); grpc_server_credentials *grpc_server_credentials_ref( grpc_server_credentials *creds); void grpc_server_credentials_unref(grpc_server_credentials *creds); /* -- Ssl credentials. -- */ typedef struct { grpc_credentials base; grpc_ssl_config config; } grpc_ssl_credentials; typedef struct { grpc_server_credentials base; grpc_ssl_server_config config; } grpc_ssl_server_credentials; /* -- Jwt credentials -- */ typedef struct { grpc_credentials base; /* Have a simple cache for now with just 1 entry. We could have a map based on the service_url for a more sophisticated one. */ gpr_mu cache_mu; struct { grpc_credentials_md_store *jwt_md; char *service_url; gpr_timespec jwt_expiration; } cached; grpc_auth_json_key key; gpr_timespec jwt_lifetime; } grpc_service_account_jwt_access_credentials; /* -- Oauth2TokenFetcher credentials -- This object is a base for credentials that need to acquire an oauth2 token from an http service. */ typedef struct grpc_credentials_metadata_request grpc_credentials_metadata_request; typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req, grpc_httpcli_context *http_context, grpc_pollset *pollset, grpc_httpcli_response_cb response_cb, gpr_timespec deadline); typedef struct { grpc_credentials base; gpr_mu mu; grpc_credentials_md_store *access_token_md; gpr_timespec token_expiration; grpc_httpcli_context httpcli_context; grpc_fetch_oauth2_func fetch_func; } grpc_oauth2_token_fetcher_credentials; /* -- GoogleRefreshToken credentials. -- */ typedef struct { grpc_oauth2_token_fetcher_credentials base; grpc_auth_refresh_token refresh_token; } grpc_google_refresh_token_credentials; /* -- Oauth2 Access Token credentials. -- */ typedef struct { grpc_credentials base; grpc_credentials_md_store *access_token_md; } grpc_access_token_credentials; /* -- Metadata-only Test credentials. -- */ typedef struct { grpc_credentials base; grpc_credentials_md_store *md_store; int is_async; } grpc_md_only_test_credentials; /* -- GoogleIAM credentials. -- */ typedef struct { grpc_credentials base; grpc_credentials_md_store *iam_md; } grpc_google_iam_credentials; /* -- Composite credentials. -- */ typedef struct { grpc_credentials base; grpc_credentials_array inner; grpc_credentials *connector_creds; } grpc_composite_credentials; #endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */ grpc-0.11.1/src/core/security/secure_endpoint.c0000644000175000017500000003426512600663151021651 0ustar apollockapollock/* * * 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/security/secure_endpoint.h" #include "src/core/support/string.h" #include #include #include #include #include #include "src/core/tsi/transport_security_interface.h" #include "src/core/debug/trace.h" #define STAGING_BUFFER_SIZE 8192 typedef struct { grpc_endpoint base; grpc_endpoint *wrapped_ep; struct tsi_frame_protector *protector; gpr_mu protector_mu; /* saved upper level callbacks and user_data. */ grpc_iomgr_closure *read_cb; grpc_iomgr_closure *write_cb; grpc_iomgr_closure on_read; gpr_slice_buffer *read_buffer; gpr_slice_buffer source_buffer; /* saved handshaker leftover data to unprotect. */ gpr_slice_buffer leftover_bytes; /* buffers for read and write */ gpr_slice read_staging_buffer; gpr_slice write_staging_buffer; gpr_slice_buffer output_buffer; gpr_refcount ref; } secure_endpoint; int grpc_trace_secure_endpoint = 0; static void destroy(secure_endpoint *secure_ep) { secure_endpoint *ep = secure_ep; grpc_endpoint_destroy(ep->wrapped_ep); tsi_frame_protector_destroy(ep->protector); gpr_slice_buffer_destroy(&ep->leftover_bytes); gpr_slice_unref(ep->read_staging_buffer); gpr_slice_unref(ep->write_staging_buffer); gpr_slice_buffer_destroy(&ep->output_buffer); gpr_slice_buffer_destroy(&ep->source_buffer); gpr_mu_destroy(&ep->protector_mu); gpr_free(ep); } /*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/ #ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG #define SECURE_ENDPOINT_UNREF(ep, reason) \ secure_endpoint_unref((ep), (reason), __FILE__, __LINE__) #define SECURE_ENDPOINT_REF(ep, reason) \ secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) static void secure_endpoint_unref(secure_endpoint *ep, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d", ep, reason, ep->ref.count, ep->ref.count - 1); if (gpr_unref(&ep->ref)) { destroy(ep); } } static void secure_endpoint_ref(secure_endpoint *ep, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d", ep, reason, ep->ref.count, ep->ref.count + 1); gpr_ref(&ep->ref); } #else #define SECURE_ENDPOINT_UNREF(ep, reason) secure_endpoint_unref((ep)) #define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep)) static void secure_endpoint_unref(secure_endpoint *ep) { if (gpr_unref(&ep->ref)) { destroy(ep); } } static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } #endif static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, gpr_uint8 **end) { gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); } static void call_read_cb(secure_endpoint *ep, int success) { if (grpc_trace_secure_endpoint) { size_t i; for (i = 0; i < ep->read_buffer->count; i++) { char *data = gpr_dump_slice(ep->read_buffer->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", ep, data); gpr_free(data); } } ep->read_buffer = NULL; ep->read_cb->cb(ep->read_cb->cb_arg, success); SECURE_ENDPOINT_UNREF(ep, "read"); } static int on_read(void *user_data, int success) { unsigned i; gpr_uint8 keep_looping = 0; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)user_data; gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); if (!success) { gpr_slice_buffer_reset_and_unref(ep->read_buffer); return 0; } /* TODO(yangg) check error, maybe bail out early */ for (i = 0; i < ep->source_buffer.count; i++) { gpr_slice encrypted = ep->source_buffer.slices[i]; gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted); size_t message_size = GPR_SLICE_LENGTH(encrypted); while (message_size > 0 || keep_looping) { size_t unprotected_buffer_size_written = (size_t)(end - cur); size_t processed_message_size = message_size; gpr_mu_lock(&ep->protector_mu); result = tsi_frame_protector_unprotect(ep->protector, message_bytes, &processed_message_size, cur, &unprotected_buffer_size_written); gpr_mu_unlock(&ep->protector_mu); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Decryption error: %s", tsi_result_to_string(result)); break; } message_bytes += processed_message_size; message_size -= processed_message_size; cur += unprotected_buffer_size_written; if (cur == end) { flush_read_staging_buffer(ep, &cur, &end); /* Force to enter the loop again to extract buffered bytes in protector. The bytes could be buffered because of running out of staging_buffer. If this happens at the end of all slices, doing another unprotect avoids leaving data in the protector. */ keep_looping = 1; } else if (unprotected_buffer_size_written > 0) { keep_looping = 1; } else { keep_looping = 0; } } if (result != TSI_OK) break; } if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) { gpr_slice_buffer_add( ep->read_buffer, gpr_slice_split_head( &ep->read_staging_buffer, (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)))); } /* TODO(yangg) experiment with moving this block after read_cb to see if it helps latency */ gpr_slice_buffer_reset_and_unref(&ep->source_buffer); if (result != TSI_OK) { gpr_slice_buffer_reset_and_unref(ep->read_buffer); return 0; } return 1; } static void on_read_cb(void *user_data, int success) { call_read_cb(user_data, on_read(user_data, success)); } static grpc_endpoint_op_status endpoint_read(grpc_endpoint *secure_ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) { secure_endpoint *ep = (secure_endpoint *)secure_ep; int immediate_read_success = -1; ep->read_cb = cb; ep->read_buffer = slices; gpr_slice_buffer_reset_and_unref(ep->read_buffer); if (ep->leftover_bytes.count) { gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); GPR_ASSERT(ep->leftover_bytes.count == 0); return on_read(ep, 1) ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; } SECURE_ENDPOINT_REF(ep, "read"); switch ( grpc_endpoint_read(ep->wrapped_ep, &ep->source_buffer, &ep->on_read)) { case GRPC_ENDPOINT_DONE: immediate_read_success = on_read(ep, 1); break; case GRPC_ENDPOINT_PENDING: return GRPC_ENDPOINT_PENDING; case GRPC_ENDPOINT_ERROR: immediate_read_success = on_read(ep, 0); break; } GPR_ASSERT(immediate_read_success != -1); SECURE_ENDPOINT_UNREF(ep, "read"); return immediate_read_success ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; } static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, gpr_uint8 **end) { gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); } static grpc_endpoint_op_status endpoint_write(grpc_endpoint *secure_ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) { unsigned i; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)secure_ep; gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); gpr_slice_buffer_reset_and_unref(&ep->output_buffer); if (grpc_trace_secure_endpoint) { for (i = 0; i < slices->count; i++) { char *data = gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data); gpr_free(data); } } for (i = 0; i < slices->count; i++) { gpr_slice plain = slices->slices[i]; gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain); size_t message_size = GPR_SLICE_LENGTH(plain); while (message_size > 0) { size_t protected_buffer_size_to_send = (size_t)(end - cur); size_t processed_message_size = message_size; gpr_mu_lock(&ep->protector_mu); result = tsi_frame_protector_protect(ep->protector, message_bytes, &processed_message_size, cur, &protected_buffer_size_to_send); gpr_mu_unlock(&ep->protector_mu); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Encryption error: %s", tsi_result_to_string(result)); break; } message_bytes += processed_message_size; message_size -= processed_message_size; cur += protected_buffer_size_to_send; if (cur == end) { flush_write_staging_buffer(ep, &cur, &end); } } if (result != TSI_OK) break; } if (result == TSI_OK) { size_t still_pending_size; do { size_t protected_buffer_size_to_send = (size_t)(end - cur); gpr_mu_lock(&ep->protector_mu); result = tsi_frame_protector_protect_flush(ep->protector, cur, &protected_buffer_size_to_send, &still_pending_size); gpr_mu_unlock(&ep->protector_mu); if (result != TSI_OK) break; cur += protected_buffer_size_to_send; if (cur == end) { flush_write_staging_buffer(ep, &cur, &end); } } while (still_pending_size > 0); if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) { gpr_slice_buffer_add( &ep->output_buffer, gpr_slice_split_head( &ep->write_staging_buffer, (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)))); } } if (result != TSI_OK) { /* TODO(yangg) do different things according to the error type? */ gpr_slice_buffer_reset_and_unref(&ep->output_buffer); return GRPC_ENDPOINT_ERROR; } return grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb); } static void endpoint_shutdown(grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; grpc_endpoint_shutdown(ep->wrapped_ep); } static void endpoint_destroy(grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; SECURE_ENDPOINT_UNREF(ep, "destroy"); } static void endpoint_add_to_pollset(grpc_endpoint *secure_ep, grpc_pollset *pollset) { secure_endpoint *ep = (secure_endpoint *)secure_ep; grpc_endpoint_add_to_pollset(ep->wrapped_ep, pollset); } static void endpoint_add_to_pollset_set(grpc_endpoint *secure_ep, grpc_pollset_set *pollset_set) { secure_endpoint *ep = (secure_endpoint *)secure_ep; grpc_endpoint_add_to_pollset_set(ep->wrapped_ep, pollset_set); } static char *endpoint_get_peer(grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; return grpc_endpoint_get_peer(ep->wrapped_ep); } static const grpc_endpoint_vtable vtable = { endpoint_read, endpoint_write, endpoint_add_to_pollset, endpoint_add_to_pollset_set, endpoint_shutdown, endpoint_destroy, endpoint_get_peer}; grpc_endpoint *grpc_secure_endpoint_create( struct tsi_frame_protector *protector, grpc_endpoint *transport, gpr_slice *leftover_slices, size_t leftover_nslices) { size_t i; secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint)); ep->base.vtable = &vtable; ep->wrapped_ep = transport; ep->protector = protector; gpr_slice_buffer_init(&ep->leftover_bytes); for (i = 0; i < leftover_nslices; i++) { gpr_slice_buffer_add(&ep->leftover_bytes, gpr_slice_ref(leftover_slices[i])); } ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); gpr_slice_buffer_init(&ep->output_buffer); gpr_slice_buffer_init(&ep->source_buffer); ep->read_buffer = NULL; grpc_iomgr_closure_init(&ep->on_read, on_read_cb, ep); gpr_mu_init(&ep->protector_mu); gpr_ref_init(&ep->ref, 1); return &ep->base; } grpc-0.11.1/src/core/security/base64.c0000644000175000017500000002010512600663151017533 0ustar apollockapollock/* * * 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/security/base64.h" #include #include #include #include /* --- Constants. --- */ static const char base64_bytes[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x3E, -1, -1, -1, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1, -1, -1, 0x7F, -1, -1, -1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1, -1, -1, -1, -1, -1, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, -1, -1, -1, -1, -1}; static const char base64_url_unsafe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char base64_url_safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; #define GRPC_BASE64_PAD_CHAR '=' #define GRPC_BASE64_PAD_BYTE 0x7F #define GRPC_BASE64_MULTILINE_LINE_LEN 76 #define GRPC_BASE64_MULTILINE_NUM_BLOCKS (GRPC_BASE64_MULTILINE_LINE_LEN / 4) /* --- base64 functions. --- */ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, int multiline) { const unsigned char *data = vdata; const char *base64_chars = url_safe ? base64_url_safe_chars : base64_url_unsafe_chars; size_t result_projected_size = 4 * ((data_size + 3) / 3) + 2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS)) : 0) + 1; char *result = gpr_malloc(result_projected_size); char *current = result; size_t num_blocks = 0; size_t i = 0; /* Encode each block. */ while (data_size >= 3) { *current++ = base64_chars[(data[i] >> 2) & 0x3F]; *current++ = base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)]; *current++ = base64_chars[((data[i + 1] & 0x0F) << 2) | ((data[i + 2] >> 6) & 0x03)]; *current++ = base64_chars[data[i + 2] & 0x3F]; data_size -= 3; i += 3; if (multiline && (++num_blocks == GRPC_BASE64_MULTILINE_NUM_BLOCKS)) { *current++ = '\r'; *current++ = '\n'; num_blocks = 0; } } /* Take care of the tail. */ if (data_size == 2) { *current++ = base64_chars[(data[i] >> 2) & 0x3F]; *current++ = base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)]; *current++ = base64_chars[(data[i + 1] & 0x0F) << 2]; *current++ = GRPC_BASE64_PAD_CHAR; } else if (data_size == 1) { *current++ = base64_chars[(data[i] >> 2) & 0x3F]; *current++ = base64_chars[(data[i] & 0x03) << 4]; *current++ = GRPC_BASE64_PAD_CHAR; *current++ = GRPC_BASE64_PAD_CHAR; } GPR_ASSERT(current >= result); GPR_ASSERT((gpr_uintptr)(current - result) < result_projected_size); result[current - result] = '\0'; return result; } gpr_slice grpc_base64_decode(const char *b64, int url_safe) { return grpc_base64_decode_with_len(b64, strlen(b64), url_safe); } static void decode_one_char(const unsigned char *codes, unsigned char *result, size_t *result_offset) { gpr_uint32 packed = (codes[0] << 2) | (codes[1] >> 4); result[(*result_offset)++] = (unsigned char)packed; } static void decode_two_chars(const unsigned char *codes, unsigned char *result, size_t *result_offset) { gpr_uint32 packed = (codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2); result[(*result_offset)++] = (unsigned char)(packed >> 8); result[(*result_offset)++] = (unsigned char)(packed); } static int decode_group(const unsigned char *codes, size_t num_codes, unsigned char *result, size_t *result_offset) { GPR_ASSERT(num_codes <= 4); /* Short end groups that may not have padding. */ if (num_codes == 1) { gpr_log(GPR_ERROR, "Invalid group. Must be at least 2 bytes."); return 0; } if (num_codes == 2) { decode_one_char(codes, result, result_offset); return 1; } if (num_codes == 3) { decode_two_chars(codes, result, result_offset); return 1; } /* Regular 4 byte groups with padding or not. */ GPR_ASSERT(num_codes == 4); if (codes[0] == GRPC_BASE64_PAD_BYTE || codes[1] == GRPC_BASE64_PAD_BYTE) { gpr_log(GPR_ERROR, "Invalid padding detected."); return 0; } if (codes[2] == GRPC_BASE64_PAD_BYTE) { if (codes[3] == GRPC_BASE64_PAD_BYTE) { decode_one_char(codes, result, result_offset); } else { gpr_log(GPR_ERROR, "Invalid padding detected."); return 0; } } else if (codes[3] == GRPC_BASE64_PAD_BYTE) { decode_two_chars(codes, result, result_offset); } else { /* No padding. */ gpr_uint32 packed = (codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3]; result[(*result_offset)++] = (unsigned char)(packed >> 16); result[(*result_offset)++] = (unsigned char)(packed >> 8); result[(*result_offset)++] = (unsigned char)(packed); } return 1; } gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, int url_safe) { gpr_slice result = gpr_slice_malloc(b64_len); unsigned char *current = GPR_SLICE_START_PTR(result); size_t result_size = 0; unsigned char codes[4]; size_t num_codes = 0; while (b64_len--) { unsigned char c = (unsigned char)(*b64++); signed char code; if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue; if (url_safe) { if (c == '+' || c == '/') { gpr_log(GPR_ERROR, "Invalid character for url safe base64 %c", c); goto fail; } if (c == '-') { c = '+'; } else if (c == '_') { c = '/'; } } code = base64_bytes[c]; if (code == -1) { if (c != '\r' && c != '\n') { gpr_log(GPR_ERROR, "Invalid character %c", c); goto fail; } } else { codes[num_codes++] = (unsigned char)code; if (num_codes == 4) { if (!decode_group(codes, num_codes, current, &result_size)) goto fail; num_codes = 0; } } } if (num_codes != 0 && !decode_group(codes, num_codes, current, &result_size)) { goto fail; } GPR_SLICE_SET_LENGTH(result, result_size); return result; fail: gpr_slice_unref(result); return gpr_empty_slice(); } grpc-0.11.1/src/core/security/secure_endpoint.h0000644000175000017500000000411112600663151021641 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H #define GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H #include "src/core/iomgr/endpoint.h" #include struct tsi_frame_protector; extern int grpc_trace_secure_endpoint; /* Takes ownership of protector and to_wrap, and refs leftover_slices. */ grpc_endpoint *grpc_secure_endpoint_create( struct tsi_frame_protector *protector, grpc_endpoint *to_wrap, gpr_slice *leftover_slices, size_t leftover_nslices); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H */ grpc-0.11.1/src/core/security/base64.h0000644000175000017500000000447412600663151017553 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_BASE64_H #define GRPC_INTERNAL_CORE_SECURITY_BASE64_H #include /* Encodes data using base64. It is the caller's responsability to free the returned char * using gpr_free. Returns NULL on NULL input. */ char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, int multiline); /* Decodes data according to the base64 specification. Returns an empty slice in case of failure. */ gpr_slice grpc_base64_decode(const char *b64, int url_safe); /* Same as above except that the length is provided by the caller. */ gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, int url_safe); #endif /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */ grpc-0.11.1/src/core/security/credentials_win32.c0000644000175000017500000000443312600663151021774 0ustar apollockapollock/* * * 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 #ifdef GPR_WIN32 #include "src/core/security/credentials.h" #include #include #include #include "src/core/support/env.h" #include "src/core/support/string.h" char *grpc_get_well_known_google_credentials_file_path(void) { char *result = NULL; char *appdata_path = gpr_getenv("APPDATA"); if (appdata_path == NULL) { gpr_log(GPR_ERROR, "Could not get APPDATA environment variable."); return NULL; } gpr_asprintf(&result, "%s/%s/%s", appdata_path, GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); gpr_free(appdata_path); return result; } #endif /* GPR_WIN32 */ grpc-0.11.1/src/core/security/secure_transport_setup.c0000644000175000017500000002554112600663151023302 0ustar apollockapollock/* * * 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/security/secure_transport_setup.h" #include #include "src/core/security/secure_endpoint.h" #include #include #include #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 typedef struct { grpc_security_connector *connector; tsi_handshaker *handshaker; unsigned char *handshake_buffer; size_t handshake_buffer_size; grpc_endpoint *wrapped_endpoint; grpc_endpoint *secure_endpoint; gpr_slice_buffer left_overs; gpr_slice_buffer incoming; gpr_slice_buffer outgoing; grpc_secure_transport_setup_done_cb cb; void *user_data; grpc_iomgr_closure on_handshake_data_sent_to_peer; grpc_iomgr_closure on_handshake_data_received_from_peer; } grpc_secure_transport_setup; static void on_handshake_data_received_from_peer(void *setup, int success); static void on_handshake_data_sent_to_peer(void *setup, int success); static void secure_transport_setup_done(grpc_secure_transport_setup *s, int is_success) { if (is_success) { s->cb(s->user_data, GRPC_SECURITY_OK, s->wrapped_endpoint, s->secure_endpoint); } else { if (s->secure_endpoint != NULL) { grpc_endpoint_shutdown(s->secure_endpoint); grpc_endpoint_destroy(s->secure_endpoint); } else { grpc_endpoint_destroy(s->wrapped_endpoint); } s->cb(s->user_data, GRPC_SECURITY_ERROR, s->wrapped_endpoint, NULL); } if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker); if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer); gpr_slice_buffer_destroy(&s->left_overs); gpr_slice_buffer_destroy(&s->outgoing); gpr_slice_buffer_destroy(&s->incoming); GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup"); gpr_free(s); } static void on_peer_checked(void *user_data, grpc_security_status status) { grpc_secure_transport_setup *s = user_data; tsi_frame_protector *protector; tsi_result result; if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Error checking peer."); secure_transport_setup_done(s, 0); return; } result = tsi_handshaker_create_frame_protector(s->handshaker, NULL, &protector); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.", tsi_result_to_string(result)); secure_transport_setup_done(s, 0); return; } s->secure_endpoint = grpc_secure_endpoint_create(protector, s->wrapped_endpoint, s->left_overs.slices, s->left_overs.count); s->left_overs.count = 0; s->left_overs.length = 0; secure_transport_setup_done(s, 1); return; } static void check_peer(grpc_secure_transport_setup *s) { grpc_security_status peer_status; tsi_peer peer; tsi_result result = tsi_handshaker_extract_peer(s->handshaker, &peer); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Peer extraction failed with error %s", tsi_result_to_string(result)); secure_transport_setup_done(s, 0); return; } peer_status = grpc_security_connector_check_peer(s->connector, peer, on_peer_checked, s); if (peer_status == GRPC_SECURITY_ERROR) { gpr_log(GPR_ERROR, "Peer check failed."); secure_transport_setup_done(s, 0); return; } else if (peer_status == GRPC_SECURITY_OK) { on_peer_checked(s, peer_status); } } static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) { size_t offset = 0; tsi_result result = TSI_OK; gpr_slice to_send; do { size_t to_send_size = s->handshake_buffer_size - offset; result = tsi_handshaker_get_bytes_to_send_to_peer( s->handshaker, s->handshake_buffer + offset, &to_send_size); offset += to_send_size; if (result == TSI_INCOMPLETE_DATA) { s->handshake_buffer_size *= 2; s->handshake_buffer = gpr_realloc(s->handshake_buffer, s->handshake_buffer_size); } } while (result == TSI_INCOMPLETE_DATA); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshake failed with error %s", tsi_result_to_string(result)); secure_transport_setup_done(s, 0); return; } to_send = gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset); gpr_slice_buffer_reset_and_unref(&s->outgoing); gpr_slice_buffer_add(&s->outgoing, to_send); /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ switch (grpc_endpoint_write(s->wrapped_endpoint, &s->outgoing, &s->on_handshake_data_sent_to_peer)) { case GRPC_ENDPOINT_ERROR: gpr_log(GPR_ERROR, "Could not send handshake data to peer."); secure_transport_setup_done(s, 0); break; case GRPC_ENDPOINT_DONE: on_handshake_data_sent_to_peer(s, 1); break; case GRPC_ENDPOINT_PENDING: break; } } static void on_handshake_data_received_from_peer(void *setup, int success) { grpc_secure_transport_setup *s = setup; size_t consumed_slice_size = 0; tsi_result result = TSI_OK; size_t i; size_t num_left_overs; int has_left_overs_in_current_slice = 0; if (!success) { gpr_log(GPR_ERROR, "Read failed."); secure_transport_setup_done(s, 0); return; } for (i = 0; i < s->incoming.count; i++) { consumed_slice_size = GPR_SLICE_LENGTH(s->incoming.slices[i]); result = tsi_handshaker_process_bytes_from_peer( s->handshaker, GPR_SLICE_START_PTR(s->incoming.slices[i]), &consumed_slice_size); if (!tsi_handshaker_is_in_progress(s->handshaker)) break; } if (tsi_handshaker_is_in_progress(s->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, &s->on_handshake_data_received_from_peer)) { case GRPC_ENDPOINT_DONE: on_handshake_data_received_from_peer(s, 1); break; case GRPC_ENDPOINT_ERROR: on_handshake_data_received_from_peer(s, 0); break; case GRPC_ENDPOINT_PENDING: break; } return; } else { send_handshake_bytes_to_peer(s); return; } } if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshake failed with error %s", tsi_result_to_string(result)); secure_transport_setup_done(s, 0); return; } /* Handshake is done and successful this point. */ has_left_overs_in_current_slice = (consumed_slice_size < GPR_SLICE_LENGTH(s->incoming.slices[i])); num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + s->incoming.count - i - 1; if (num_left_overs == 0) { check_peer(s); return; } /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { gpr_slice_buffer_add( &s->left_overs, gpr_slice_split_tail(&s->incoming.slices[i], consumed_slice_size)); gpr_slice_unref( s->incoming.slices[i]); /* split_tail above increments refcount. */ } gpr_slice_buffer_addn( &s->left_overs, &s->incoming.slices[i + 1], num_left_overs - (size_t)has_left_overs_in_current_slice); check_peer(s); } /* If setup is NULL, the setup is done. */ static void on_handshake_data_sent_to_peer(void *setup, int success) { grpc_secure_transport_setup *s = setup; /* Make sure that write is OK. */ if (!success) { gpr_log(GPR_ERROR, "Write failed."); if (setup != NULL) secure_transport_setup_done(s, 0); return; } /* We may be done. */ if (tsi_handshaker_is_in_progress(s->handshaker)) { /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, &s->on_handshake_data_received_from_peer)) { case GRPC_ENDPOINT_ERROR: on_handshake_data_received_from_peer(s, 0); break; case GRPC_ENDPOINT_PENDING: break; case GRPC_ENDPOINT_DONE: on_handshake_data_received_from_peer(s, 1); break; } } else { check_peer(s); } } void grpc_setup_secure_transport(grpc_security_connector *connector, grpc_endpoint *nonsecure_endpoint, grpc_secure_transport_setup_done_cb cb, void *user_data) { grpc_security_status result = GRPC_SECURITY_OK; grpc_secure_transport_setup *s = gpr_malloc(sizeof(grpc_secure_transport_setup)); memset(s, 0, sizeof(grpc_secure_transport_setup)); result = grpc_security_connector_create_handshaker(connector, &s->handshaker); if (result != GRPC_SECURITY_OK) { secure_transport_setup_done(s, 0); return; } s->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "secure_transport_setup"); s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; s->handshake_buffer = gpr_malloc(s->handshake_buffer_size); s->wrapped_endpoint = nonsecure_endpoint; s->user_data = user_data; s->cb = cb; grpc_iomgr_closure_init(&s->on_handshake_data_sent_to_peer, on_handshake_data_sent_to_peer, s); grpc_iomgr_closure_init(&s->on_handshake_data_received_from_peer, on_handshake_data_received_from_peer, s); gpr_slice_buffer_init(&s->left_overs); gpr_slice_buffer_init(&s->outgoing); gpr_slice_buffer_init(&s->incoming); send_handshake_bytes_to_peer(s); } grpc-0.11.1/src/core/security/security_connector.h0000644000175000017500000002216512600663151022405 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H #define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H #include #include "src/core/iomgr/endpoint.h" #include "src/core/tsi/transport_security_interface.h" /* --- status enum. --- */ typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_PENDING, GRPC_SECURITY_ERROR } grpc_security_status; /* --- URL schemes. --- */ #define GRPC_SSL_URL_SCHEME "https" #define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" /* --- security_connector object. --- A security connector object represents away to configure the underlying transport security mechanism and check the resulting trusted peer. */ typedef struct grpc_security_connector grpc_security_connector; #define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector" typedef void (*grpc_security_check_cb)(void *user_data, grpc_security_status status); typedef struct { void (*destroy)(grpc_security_connector *sc); grpc_security_status (*create_handshaker)(grpc_security_connector *sc, tsi_handshaker **handshaker); grpc_security_status (*check_peer)(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data); } grpc_security_connector_vtable; struct grpc_security_connector { const grpc_security_connector_vtable *vtable; gpr_refcount refcount; int is_client_side; const char *url_scheme; grpc_auth_context *auth_context; /* Populated after the peer is checked. */ }; /* Refcounting. */ #ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG #define GRPC_SECURITY_CONNECTOR_REF(p, r) \ grpc_security_connector_ref((p), __FILE__, __LINE__, (r)) #define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \ grpc_security_connector_unref((p), __FILE__, __LINE__, (r)) grpc_security_connector *grpc_security_connector_ref( grpc_security_connector *policy, const char *file, int line, const char *reason); void grpc_security_connector_unref(grpc_security_connector *policy, const char *file, int line, const char *reason); #else #define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p)) #define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p)) grpc_security_connector *grpc_security_connector_ref( grpc_security_connector *policy); void grpc_security_connector_unref(grpc_security_connector *policy); #endif /* Handshake creation. */ grpc_security_status grpc_security_connector_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker); /* Check the peer. Implementations can choose to check the peer either synchronously or asynchronously. In the first case, a successful call will return GRPC_SECURITY_OK. In the asynchronous case, the call will return GRPC_SECURITY_PENDING unless an error is detected early on. Ownership of the peer is transfered. */ grpc_security_status grpc_security_connector_check_peer( grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data); /* Util to encapsulate the connector in a channel arg. */ grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); /* Util to get the connector from a channel arg. */ grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg); /* Util to find the connector from channel args. */ grpc_security_connector *grpc_find_security_connector_in_args( const grpc_channel_args *args); /* --- channel_security_connector object. --- A channel security connector object represents away to configure the underlying transport security mechanism on the client side. */ typedef struct grpc_channel_security_connector grpc_channel_security_connector; struct grpc_channel_security_connector { grpc_security_connector base; /* requires is_client_side to be non 0. */ grpc_credentials *request_metadata_creds; grpc_security_status (*check_call_host)(grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data); }; /* Checks that the host that will be set for a call is acceptable. Implementations can choose do the check either synchronously or asynchronously. In the first case, a successful call will return GRPC_SECURITY_OK. In the asynchronous case, the call will return GRPC_SECURITY_PENDING unless an error is detected early on. */ grpc_security_status grpc_channel_security_connector_check_call_host( grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data); /* --- Creation security connectors. --- */ /* For TESTING ONLY! Creates a fake connector that emulates real channel security. */ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_credentials *request_metadata_creds, int call_host_check_is_async); /* For TESTING ONLY! Creates a fake connector that emulates real server security. */ grpc_security_connector *grpc_fake_server_security_connector_create(void); /* Config for ssl clients. */ typedef struct { unsigned char *pem_private_key; size_t pem_private_key_size; unsigned char *pem_cert_chain; size_t pem_cert_chain_size; unsigned char *pem_root_certs; size_t pem_root_certs_size; } grpc_ssl_config; /* Creates an SSL channel_security_connector. - request_metadata_creds is the credentials object which metadata will be sent with each request. This parameter can be NULL. - config is the SSL config to be used for the SSL channel establishment. - is_client should be 0 for a server or a non-0 value for a client. - secure_peer_name is the secure peer name that should be checked in grpc_channel_security_connector_check_peer. This parameter may be NULL in which case the peer name will not be checked. Note that if this parameter is not NULL, then, pem_root_certs should not be NULL either. - sc is a pointer on the connector to be created. This function returns GRPC_SECURITY_OK in case of success or a specific error code otherwise. */ grpc_security_status grpc_ssl_channel_security_connector_create( grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc); /* Gets the default ssl roots. */ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); /* Config for ssl servers. */ typedef struct { unsigned char **pem_private_keys; size_t *pem_private_keys_sizes; unsigned char **pem_cert_chains; size_t *pem_cert_chains_sizes; size_t num_key_cert_pairs; unsigned char *pem_root_certs; size_t pem_root_certs_size; int force_client_auth; } grpc_ssl_server_config; /* Creates an SSL server_security_connector. - config is the SSL config to be used for the SSL channel establishment. - sc is a pointer on the connector to be created. This function returns GRPC_SECURITY_OK in case of success or a specific error code otherwise. */ grpc_security_status grpc_ssl_server_security_connector_create( const grpc_ssl_server_config *config, grpc_security_connector **sc); /* Util. */ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, const char *name); /* Exposed for testing only. */ grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */ grpc-0.11.1/src/core/security/security_connector.c0000644000175000017500000006154412600663151022404 0ustar apollockapollock/* * * 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/security/security_connector.h" #include #include "src/core/security/credentials.h" #include "src/core/security/secure_endpoint.h" #include "src/core/security/security_context.h" #include "src/core/support/env.h" #include "src/core/support/file.h" #include "src/core/support/string.h" #include "src/core/transport/chttp2/alpn.h" #include #include #include #include #include #include "src/core/tsi/fake_transport_security.h" #include "src/core/tsi/ssl_transport_security.h" /* -- Constants. -- */ #ifndef INSTALL_PREFIX static const char *installed_roots_path = "/usr/share/grpc/roots.pem"; #else static const char *installed_roots_path = INSTALL_PREFIX "/share/grpc/roots.pem"; #endif /* -- Cipher suites. -- */ /* Defines the cipher suites that we accept by default. All these cipher suites are compliant with HTTP2. */ #define GRPC_SSL_CIPHER_SUITES \ "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \ "SHA384:ECDHE-RSA-AES256-GCM-SHA384" static gpr_once cipher_suites_once = GPR_ONCE_INIT; static const char *cipher_suites = NULL; static void init_cipher_suites(void) { char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES"); cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES; } static const char *ssl_cipher_suites(void) { gpr_once_init(&cipher_suites_once, init_cipher_suites); return cipher_suites; } /* -- Common methods. -- */ /* Returns the first property with that name. */ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, const char *name) { size_t i; if (peer == NULL) return NULL; for (i = 0; i < peer->property_count; i++) { const tsi_peer_property *property = &peer->properties[i]; if (name == NULL && property->name == NULL) { return property; } if (name != NULL && property->name != NULL && strcmp(property->name, name) == 0) { return property; } } return NULL; } grpc_security_status grpc_security_connector_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { if (sc == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR; return sc->vtable->create_handshaker(sc, handshaker); } grpc_security_status grpc_security_connector_check_peer( grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { if (sc == NULL) { tsi_peer_destruct(&peer); return GRPC_SECURITY_ERROR; } return sc->vtable->check_peer(sc, peer, cb, user_data); } grpc_security_status grpc_channel_security_connector_check_call_host( grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data) { if (sc == NULL || sc->check_call_host == NULL) return GRPC_SECURITY_ERROR; return sc->check_call_host(sc, host, cb, user_data); } #ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG grpc_security_connector *grpc_security_connector_ref( grpc_security_connector *sc, const char *file, int line, const char *reason) { if (sc == NULL) return NULL; gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECURITY_CONNECTOR:%p ref %d -> %d %s", sc, (int)sc->refcount.count, (int)sc->refcount.count + 1, reason); #else grpc_security_connector *grpc_security_connector_ref( grpc_security_connector *sc) { if (sc == NULL) return NULL; #endif gpr_ref(&sc->refcount); return sc; } #ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG void grpc_security_connector_unref(grpc_security_connector *sc, const char *file, int line, const char *reason) { if (sc == NULL) return; gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc, (int)sc->refcount.count, (int)sc->refcount.count - 1, reason); #else void grpc_security_connector_unref(grpc_security_connector *sc) { if (sc == NULL) return; #endif if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); } static void connector_pointer_arg_destroy(void *p) { GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg"); } static void *connector_pointer_arg_copy(void *p) { return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg"); } grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { grpc_arg result; result.type = GRPC_ARG_POINTER; result.key = GRPC_SECURITY_CONNECTOR_ARG; result.value.pointer.destroy = connector_pointer_arg_destroy; result.value.pointer.copy = connector_pointer_arg_copy; result.value.pointer.p = sc; return result; } grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL; if (arg->type != GRPC_ARG_POINTER) { gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, GRPC_SECURITY_CONNECTOR_ARG); return NULL; } return arg->value.pointer.p; } grpc_security_connector *grpc_find_security_connector_in_args( const grpc_channel_args *args) { size_t i; if (args == NULL) return NULL; for (i = 0; i < args->num_args; i++) { grpc_security_connector *sc = grpc_security_connector_from_arg(&args->args[i]); if (sc != NULL) return sc; } return NULL; } static int check_request_metadata_creds(grpc_credentials *creds) { if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) { gpr_log(GPR_ERROR, "Incompatible credentials for channel security connector: needs to " "set request metadata."); return 0; } return 1; } /* -- Fake implementation. -- */ typedef struct { grpc_channel_security_connector base; int call_host_check_is_async; } grpc_fake_channel_security_connector; static void fake_channel_destroy(grpc_security_connector *sc) { grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; grpc_credentials_unref(c->request_metadata_creds); GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); gpr_free(sc); } static void fake_server_destroy(grpc_security_connector *sc) { GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); gpr_free(sc); } static grpc_security_status fake_channel_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { *handshaker = tsi_create_fake_handshaker(1); return GRPC_SECURITY_OK; } static grpc_security_status fake_server_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { *handshaker = tsi_create_fake_handshaker(0); return GRPC_SECURITY_OK; } static grpc_security_status fake_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { const char *prop_name; grpc_security_status status = GRPC_SECURITY_OK; if (peer.property_count != 1) { gpr_log(GPR_ERROR, "Fake peers should only have 1 property."); status = GRPC_SECURITY_ERROR; goto end; } prop_name = peer.properties[0].name; if (prop_name == NULL || strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) { gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.", prop_name == NULL ? "" : prop_name); status = GRPC_SECURITY_ERROR; goto end; } if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE, peer.properties[0].value.length)) { gpr_log(GPR_ERROR, "Invalid value for cert type property."); status = GRPC_SECURITY_ERROR; goto end; } GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); sc->auth_context = grpc_auth_context_create(NULL); grpc_auth_context_add_cstring_property( sc->auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_FAKE_TRANSPORT_SECURITY_TYPE); end: tsi_peer_destruct(&peer); return status; } static grpc_security_status fake_channel_check_call_host( grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data) { grpc_fake_channel_security_connector *c = (grpc_fake_channel_security_connector *)sc; if (c->call_host_check_is_async) { cb(user_data, GRPC_SECURITY_OK); return GRPC_SECURITY_PENDING; } else { return GRPC_SECURITY_OK; } } static grpc_security_connector_vtable fake_channel_vtable = { fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer}; static grpc_security_connector_vtable fake_server_vtable = { fake_server_destroy, fake_server_create_handshaker, fake_check_peer}; grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_credentials *request_metadata_creds, int call_host_check_is_async) { grpc_fake_channel_security_connector *c = gpr_malloc(sizeof(grpc_fake_channel_security_connector)); memset(c, 0, sizeof(grpc_fake_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.base.vtable = &fake_channel_vtable; GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); c->base.check_call_host = fake_channel_check_call_host; c->call_host_check_is_async = call_host_check_is_async; return &c->base; } grpc_security_connector *grpc_fake_server_security_connector_create(void) { grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector)); memset(c, 0, sizeof(grpc_security_connector)); gpr_ref_init(&c->refcount, 1); c->is_client_side = 0; c->vtable = &fake_server_vtable; c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; return c; } /* --- Ssl implementation. --- */ typedef struct { grpc_channel_security_connector base; tsi_ssl_handshaker_factory *handshaker_factory; char *target_name; char *overridden_target_name; tsi_peer peer; } grpc_ssl_channel_security_connector; typedef struct { grpc_security_connector base; tsi_ssl_handshaker_factory *handshaker_factory; } grpc_ssl_server_security_connector; static void ssl_channel_destroy(grpc_security_connector *sc) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; grpc_credentials_unref(c->base.request_metadata_creds); if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } if (c->target_name != NULL) gpr_free(c->target_name); if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); tsi_peer_destruct(&c->peer); GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); gpr_free(sc); } static void ssl_server_destroy(grpc_security_connector *sc) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); gpr_free(sc); } static grpc_security_status ssl_create_handshaker( tsi_ssl_handshaker_factory *handshaker_factory, int is_client, const char *peer_name, tsi_handshaker **handshaker) { tsi_result result = TSI_OK; if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR; result = tsi_ssl_handshaker_factory_create_handshaker( handshaker_factory, is_client ? peer_name : NULL, handshaker); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", tsi_result_to_string(result)); return GRPC_SECURITY_ERROR; } return GRPC_SECURITY_OK; } static grpc_security_status ssl_channel_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; return ssl_create_handshaker(c->handshaker_factory, 1, c->overridden_target_name != NULL ? c->overridden_target_name : c->target_name, handshaker); } static grpc_security_status ssl_server_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker); } static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { char *allocated_name = NULL; int r; if (strchr(peer_name, ':') != NULL) { char *ignored_port; gpr_split_host_port(peer_name, &allocated_name, &ignored_port); gpr_free(ignored_port); peer_name = allocated_name; if (!peer_name) return 0; } r = tsi_ssl_peer_matches_name(peer, peer_name); gpr_free(allocated_name); return r; } grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { size_t i; grpc_auth_context *ctx = NULL; const char *peer_identity_property_name = NULL; /* The caller has checked the certificate type property. */ GPR_ASSERT(peer->property_count >= 1); ctx = grpc_auth_context_create(NULL); grpc_auth_context_add_cstring_property( ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_SSL_TRANSPORT_SECURITY_TYPE); for (i = 0; i < peer->property_count; i++) { const tsi_peer_property *prop = &peer->properties[i]; if (prop->name == NULL) continue; if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { /* If there is no subject alt name, have the CN as the identity. */ if (peer_identity_property_name == NULL) { peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; } grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length); } else if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length); } } if (peer_identity_property_name != NULL) { GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( ctx, peer_identity_property_name) == 1); } return ctx; } static grpc_security_status ssl_check_peer(grpc_security_connector *sc, const char *peer_name, const tsi_peer *peer) { /* Check the ALPN. */ const tsi_peer_property *p = tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); if (p == NULL) { gpr_log(GPR_ERROR, "Missing selected ALPN property."); return GRPC_SECURITY_ERROR; } if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) { gpr_log(GPR_ERROR, "Invalid ALPN value."); return GRPC_SECURITY_ERROR; } /* Check the peer name if specified. */ if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); return GRPC_SECURITY_ERROR; } if (sc->auth_context != NULL) { GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); } sc->auth_context = tsi_ssl_peer_to_auth_context(peer); return GRPC_SECURITY_OK; } static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; grpc_security_status status; tsi_peer_destruct(&c->peer); c->peer = peer; status = ssl_check_peer(sc, c->overridden_target_name != NULL ? c->overridden_target_name : c->target_name, &peer); return status; } static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { grpc_security_status status = ssl_check_peer(sc, NULL, &peer); tsi_peer_destruct(&peer); return status; } static grpc_security_status ssl_channel_check_call_host( grpc_channel_security_connector *sc, const char *host, grpc_security_check_cb cb, void *user_data) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK; /* If the target name was overridden, then the original target_name was 'checked' transitively during the previous peer check at the end of the handshake. */ if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) { return GRPC_SECURITY_OK; } else { return GRPC_SECURITY_ERROR; } } static grpc_security_connector_vtable ssl_channel_vtable = { ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer}; static grpc_security_connector_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer}; static gpr_slice default_pem_root_certs; static void init_default_pem_root_certs(void) { /* First try to load the roots from the environment. */ char *default_root_certs_path = gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); if (default_root_certs_path == NULL) { default_pem_root_certs = gpr_empty_slice(); } else { default_pem_root_certs = gpr_load_file(default_root_certs_path, 0, NULL); gpr_free(default_root_certs_path); } /* Fall back to installed certs if needed. */ if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) { default_pem_root_certs = gpr_load_file(installed_roots_path, 0, NULL); } } size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in loading all the roots once for the lifetime of the process. */ static gpr_once once = GPR_ONCE_INIT; gpr_once_init(&once, init_default_pem_root_certs); *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs); return GPR_SLICE_LENGTH(default_pem_root_certs); } grpc_security_status grpc_ssl_channel_security_connector_create( grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const unsigned char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); unsigned char *alpn_protocol_string_lengths = gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_channel_security_connector *c; size_t i; const unsigned char *pem_root_certs; size_t pem_root_certs_size; char *port; for (i = 0; i < num_alpn_protocols; i++) { alpn_protocol_strings[i] = (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); alpn_protocol_string_lengths[i] = (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); } if (config == NULL || target_name == NULL) { gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); goto error; } if (!check_request_metadata_creds(request_metadata_creds)) { goto error; } if (config->pem_root_certs == NULL) { pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); if (pem_root_certs == NULL || pem_root_certs_size == 0) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); goto error; } } else { pem_root_certs = config->pem_root_certs; pem_root_certs_size = config->pem_root_certs_size; } c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector)); memset(c, 0, sizeof(grpc_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; gpr_split_host_port(target_name, &c->target_name, &port); gpr_free(port); if (overridden_target_name != NULL) { c->overridden_target_name = gpr_strdup(overridden_target_name); } result = tsi_create_ssl_client_handshaker_factory( config->pem_private_key, config->pem_private_key_size, config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); ssl_channel_destroy(&c->base.base); *sc = NULL; goto error; } *sc = &c->base; gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; } grpc_security_status grpc_ssl_server_security_connector_create( const grpc_ssl_server_config *config, grpc_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const unsigned char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); unsigned char *alpn_protocol_string_lengths = gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_server_security_connector *c; size_t i; for (i = 0; i < num_alpn_protocols; i++) { alpn_protocol_strings[i] = (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); alpn_protocol_string_lengths[i] = (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); } if (config == NULL || config->num_key_cert_pairs == 0) { gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); goto error; } c = gpr_malloc(sizeof(grpc_ssl_server_security_connector)); memset(c, 0, sizeof(grpc_ssl_server_security_connector)); gpr_ref_init(&c->base.refcount, 1); c->base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.vtable = &ssl_server_vtable; result = tsi_create_ssl_server_handshaker_factory( (const unsigned char **)config->pem_private_keys, config->pem_private_keys_sizes, (const unsigned char **)config->pem_cert_chains, config->pem_cert_chains_sizes, config->num_key_cert_pairs, config->pem_root_certs, config->pem_root_certs_size, config->force_client_auth, ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); ssl_server_destroy(&c->base); *sc = NULL; goto error; } *sc = &c->base; gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; } grpc-0.11.1/src/core/security/server_secure_chttp2.c0000644000175000017500000002322312600663151022613 0ustar apollockapollock/* * * 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 #include #include "src/core/channel/channel_args.h" #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_server.h" #include "src/core/security/auth_filters.h" #include "src/core/security/credentials.h" #include "src/core/security/security_connector.h" #include "src/core/security/security_context.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/surface/server.h" #include "src/core/transport/chttp2_transport.h" #include #include #include #include typedef struct tcp_endpoint_list { grpc_endpoint *tcp_endpoint; struct tcp_endpoint_list *next; } tcp_endpoint_list; typedef struct grpc_server_secure_state { grpc_server *server; grpc_tcp_server *tcp; grpc_security_connector *sc; grpc_server_credentials *creds; tcp_endpoint_list *handshaking_tcp_endpoints; int is_shutdown; gpr_mu mu; gpr_refcount refcount; } grpc_server_secure_state; static void state_ref(grpc_server_secure_state *state) { gpr_ref(&state->refcount); } static void state_unref(grpc_server_secure_state *state) { if (gpr_unref(&state->refcount)) { /* ensure all threads have unlocked */ gpr_mu_lock(&state->mu); gpr_mu_unlock(&state->mu); /* clean up */ GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server"); grpc_server_credentials_unref(state->creds); gpr_free(state); } } static void setup_transport(void *statep, grpc_transport *transport, grpc_mdctx *mdctx) { static grpc_channel_filter const *extra_filters[] = { &grpc_server_auth_filter, &grpc_http_server_filter}; grpc_server_secure_state *state = statep; grpc_channel_args *args_copy; grpc_arg args_to_add[2]; args_to_add[0] = grpc_security_connector_to_arg(state->sc); args_to_add[1] = grpc_auth_metadata_processor_to_arg(&state->creds->processor); args_copy = grpc_channel_args_copy_and_add( grpc_server_get_channel_args(state->server), args_to_add, GPR_ARRAY_SIZE(args_to_add)); grpc_server_setup_transport(state->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy); grpc_channel_args_destroy(args_copy); } static int remove_tcp_from_list_locked(grpc_server_secure_state *state, grpc_endpoint *tcp) { tcp_endpoint_list *node = state->handshaking_tcp_endpoints; tcp_endpoint_list *tmp = NULL; if (node && node->tcp_endpoint == tcp) { state->handshaking_tcp_endpoints = state->handshaking_tcp_endpoints->next; gpr_free(node); return 0; } while (node) { if (node->next->tcp_endpoint == tcp) { tmp = node->next; node->next = node->next->next; gpr_free(tmp); return 0; } node = node->next; } return -1; } static void on_secure_transport_setup_done(void *statep, grpc_security_status status, grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint) { grpc_server_secure_state *state = statep; grpc_transport *transport; grpc_mdctx *mdctx; if (status == GRPC_SECURITY_OK) { gpr_mu_lock(&state->mu); remove_tcp_from_list_locked(state, wrapped_endpoint); if (!state->is_shutdown) { mdctx = grpc_mdctx_create(); transport = grpc_create_chttp2_transport( grpc_server_get_channel_args(state->server), secure_endpoint, mdctx, 0); setup_transport(state, transport, mdctx); grpc_chttp2_transport_start_reading(transport, NULL, 0); } else { /* We need to consume this here, because the server may already have gone * away. */ grpc_endpoint_destroy(secure_endpoint); } gpr_mu_unlock(&state->mu); } else { gpr_mu_lock(&state->mu); remove_tcp_from_list_locked(state, wrapped_endpoint); gpr_mu_unlock(&state->mu); gpr_log(GPR_ERROR, "Secure transport failed with error %d", status); } state_unref(state); } static void on_accept(void *statep, grpc_endpoint *tcp) { grpc_server_secure_state *state = statep; tcp_endpoint_list *node; state_ref(state); node = gpr_malloc(sizeof(tcp_endpoint_list)); node->tcp_endpoint = tcp; gpr_mu_lock(&state->mu); node->next = state->handshaking_tcp_endpoints; state->handshaking_tcp_endpoints = node; gpr_mu_unlock(&state->mu); grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done, state); } /* Server callback: start listening on our ports */ static void start(grpc_server *server, void *statep, grpc_pollset **pollsets, size_t pollset_count) { grpc_server_secure_state *state = statep; grpc_tcp_server_start(state->tcp, pollsets, pollset_count, on_accept, state); } static void destroy_done(void *statep) { grpc_server_secure_state *state = statep; grpc_server_listener_destroy_done(state->server); gpr_mu_lock(&state->mu); while (state->handshaking_tcp_endpoints != NULL) { grpc_endpoint_shutdown(state->handshaking_tcp_endpoints->tcp_endpoint); remove_tcp_from_list_locked(state, state->handshaking_tcp_endpoints->tcp_endpoint); } gpr_mu_unlock(&state->mu); state_unref(state); } /* Server callback: destroy the tcp listener (so we don't generate further callbacks) */ static void destroy(grpc_server *server, void *statep) { grpc_server_secure_state *state = statep; grpc_tcp_server *tcp; gpr_mu_lock(&state->mu); state->is_shutdown = 1; tcp = state->tcp; gpr_mu_unlock(&state->mu); grpc_tcp_server_destroy(tcp, destroy_done, state); } int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; grpc_server_secure_state *state = NULL; size_t i; unsigned count = 0; int port_num = -1; int port_temp; grpc_security_status status = GRPC_SECURITY_ERROR; grpc_security_connector *sc = NULL; /* create security context */ if (creds == NULL) goto error; status = grpc_server_credentials_create_security_connector(creds, &sc); if (status != GRPC_SECURITY_OK) { gpr_log(GPR_ERROR, "Unable to create secure server with credentials of type %s.", creds->type); goto error; } /* resolve address */ resolved = grpc_blocking_resolve_address(addr, "https"); if (!resolved) { goto error; } tcp = grpc_tcp_server_create(); if (!tcp) { goto error; } for (i = 0; i < resolved->naddrs; i++) { port_temp = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len); if (port_temp >= 0) { if (port_num == -1) { port_num = port_temp; } else { GPR_ASSERT(port_num == port_temp); } count++; } } if (count == 0) { gpr_log(GPR_ERROR, "No address added out of total %d resolved", resolved->naddrs); goto error; } if (count != resolved->naddrs) { gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", count, resolved->naddrs); /* if it's an error, don't we want to goto error; here ? */ } grpc_resolved_addresses_destroy(resolved); state = gpr_malloc(sizeof(*state)); memset(state, 0, sizeof(*state)); state->server = server; state->tcp = tcp; state->sc = sc; state->creds = grpc_server_credentials_ref(creds); state->handshaking_tcp_endpoints = NULL; state->is_shutdown = 0; gpr_mu_init(&state->mu); gpr_ref_init(&state->refcount, 1); /* Register with the server only upon success */ grpc_server_add_listener(server, state, start, destroy); return port_num; /* Error path: cleanup and return */ error: if (sc) { GRPC_SECURITY_CONNECTOR_UNREF(sc, "server"); } if (resolved) { grpc_resolved_addresses_destroy(resolved); } if (tcp) { grpc_tcp_server_destroy(tcp, NULL, NULL); } if (state) { gpr_free(state); } return 0; } grpc-0.11.1/src/core/security/credentials.c0000644000175000017500000013006012600663151020746 0ustar apollockapollock/* * * 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/security/credentials.h" #include #include #include "src/core/channel/channel_args.h" #include "src/core/channel/http_client_filter.h" #include "src/core/json/json.h" #include "src/core/httpcli/httpcli.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/string.h" #include #include #include #include #include /* -- Common. -- */ struct grpc_credentials_metadata_request { grpc_credentials *creds; grpc_credentials_metadata_cb cb; grpc_iomgr_closure *on_simulated_token_fetch_done_closure; void *user_data; }; static grpc_credentials_metadata_request * grpc_credentials_metadata_request_create(grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { grpc_credentials_metadata_request *r = gpr_malloc(sizeof(grpc_credentials_metadata_request)); r->creds = grpc_credentials_ref(creds); r->cb = cb; r->on_simulated_token_fetch_done_closure = gpr_malloc(sizeof(grpc_iomgr_closure)); r->user_data = user_data; return r; } static void grpc_credentials_metadata_request_destroy( grpc_credentials_metadata_request *r) { grpc_credentials_unref(r->creds); gpr_free(r->on_simulated_token_fetch_done_closure); gpr_free(r); } grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) { if (creds == NULL) return NULL; gpr_ref(&creds->refcount); return creds; } void grpc_credentials_unref(grpc_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { creds->vtable->destruct(creds); gpr_free(creds); } } void grpc_credentials_release(grpc_credentials *creds) { grpc_credentials_unref(creds); } int grpc_credentials_has_request_metadata(grpc_credentials *creds) { if (creds == NULL) return 0; return creds->vtable->has_request_metadata(creds); } int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) { if (creds == NULL) return 0; return creds->vtable->has_request_metadata_only(creds); } void grpc_credentials_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { if (creds == NULL || !grpc_credentials_has_request_metadata(creds) || creds->vtable->get_request_metadata == NULL) { if (cb != NULL) { cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK); } return; } creds->vtable->get_request_metadata(creds, pollset, service_url, cb, user_data); } grpc_security_status grpc_credentials_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { *new_args = NULL; if (creds == NULL || creds->vtable->create_security_connector == NULL || grpc_credentials_has_request_metadata_only(creds)) { gpr_log(GPR_ERROR, "Invalid credentials for creating a security connector."); return GRPC_SECURITY_ERROR; } return creds->vtable->create_security_connector( creds, target, args, request_metadata_creds, sc, new_args); } grpc_server_credentials *grpc_server_credentials_ref( grpc_server_credentials *creds) { if (creds == NULL) return NULL; gpr_ref(&creds->refcount); return creds; } void grpc_server_credentials_unref(grpc_server_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { creds->vtable->destruct(creds); if (creds->processor.destroy != NULL && creds->processor.state != NULL) { creds->processor.destroy(creds->processor.state); } gpr_free(creds); } } void grpc_server_credentials_release(grpc_server_credentials *creds) { grpc_server_credentials_unref(creds); } grpc_security_status grpc_server_credentials_create_security_connector( grpc_server_credentials *creds, grpc_security_connector **sc) { if (creds == NULL || creds->vtable->create_security_connector == NULL) { gpr_log(GPR_ERROR, "Server credentials cannot create security context."); return GRPC_SECURITY_ERROR; } return creds->vtable->create_security_connector(creds, sc); } void grpc_server_credentials_set_auth_metadata_processor( grpc_server_credentials *creds, grpc_auth_metadata_processor processor) { if (creds == NULL) return; if (creds->processor.destroy != NULL && creds->processor.state != NULL) { creds->processor.destroy(creds->processor.state); } creds->processor = processor; } /* -- Ssl credentials. -- */ static void ssl_destruct(grpc_credentials *creds) { grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key); if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain); } static void ssl_server_destruct(grpc_server_credentials *creds) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; size_t i; for (i = 0; i < c->config.num_key_cert_pairs; i++) { if (c->config.pem_private_keys[i] != NULL) { gpr_free(c->config.pem_private_keys[i]); } if (c->config.pem_cert_chains[i] != NULL) { gpr_free(c->config.pem_cert_chains[i]); } } if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys); if (c->config.pem_private_keys_sizes != NULL) { gpr_free(c->config.pem_private_keys_sizes); } if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains); if (c->config.pem_cert_chains_sizes != NULL) { gpr_free(c->config.pem_cert_chains_sizes); } if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); } static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; } static int ssl_has_request_metadata_only(const grpc_credentials *creds) { return 0; } static grpc_security_status ssl_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; grpc_security_status status = GRPC_SECURITY_OK; size_t i = 0; const char *overridden_target_name = NULL; grpc_arg arg; for (i = 0; args && i < args->num_args; i++) { grpc_arg *arg = &args->args[i]; if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && arg->type == GRPC_ARG_STRING) { overridden_target_name = arg->value.string; break; } } status = grpc_ssl_channel_security_connector_create( request_metadata_creds, &c->config, target, overridden_target_name, sc); if (status != GRPC_SECURITY_OK) { return status; } arg.type = GRPC_ARG_STRING; arg.key = GRPC_ARG_HTTP2_SCHEME; arg.value.string = "https"; *new_args = grpc_channel_args_copy_and_add(args, &arg, 1); return status; } static grpc_security_status ssl_server_create_security_connector( grpc_server_credentials *creds, grpc_security_connector **sc) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; return grpc_ssl_server_security_connector_create(&c->config, sc); } static grpc_credentials_vtable ssl_vtable = { ssl_destruct, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL, ssl_create_security_connector}; static grpc_server_credentials_vtable ssl_server_vtable = { ssl_server_destruct, ssl_server_create_security_connector}; static void ssl_copy_key_material(const char *input, unsigned char **output, size_t *output_size) { *output_size = strlen(input); *output = gpr_malloc(*output_size); memcpy(*output, input, *output_size); } static void ssl_build_config(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, grpc_ssl_config *config) { if (pem_root_certs != NULL) { ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, &config->pem_root_certs_size); } if (pem_key_cert_pair != NULL) { GPR_ASSERT(pem_key_cert_pair->private_key != NULL); GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL); ssl_copy_key_material(pem_key_cert_pair->private_key, &config->pem_private_key, &config->pem_private_key_size); ssl_copy_key_material(pem_key_cert_pair->cert_chain, &config->pem_cert_chain, &config->pem_cert_chain_size); } } static void ssl_build_server_config( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, grpc_ssl_server_config *config) { size_t i; config->force_client_auth = force_client_auth; if (pem_root_certs != NULL) { ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, &config->pem_root_certs_size); } if (num_key_cert_pairs > 0) { GPR_ASSERT(pem_key_cert_pairs != NULL); config->pem_private_keys = gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); config->pem_cert_chains = gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); config->pem_private_keys_sizes = gpr_malloc(num_key_cert_pairs * sizeof(size_t)); config->pem_cert_chains_sizes = gpr_malloc(num_key_cert_pairs * sizeof(size_t)); } config->num_key_cert_pairs = num_key_cert_pairs; for (i = 0; i < num_key_cert_pairs; i++) { GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); ssl_copy_key_material(pem_key_cert_pairs[i].private_key, &config->pem_private_keys[i], &config->pem_private_keys_sizes[i]); ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain, &config->pem_cert_chains[i], &config->pem_cert_chains_sizes[i]); } } grpc_credentials *grpc_ssl_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved) { grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_ssl_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_SSL; c->base.vtable = &ssl_vtable; gpr_ref_init(&c->base.refcount, 1); ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config); return &c->base; } grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved) { grpc_ssl_server_credentials *c = gpr_malloc(sizeof(grpc_ssl_server_credentials)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_ssl_server_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_SSL; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &ssl_server_vtable; ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, num_key_cert_pairs, force_client_auth, &c->config); return &c->base; } /* -- Jwt credentials -- */ static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { if (c->cached.jwt_md != NULL) { grpc_credentials_md_store_unref(c->cached.jwt_md); c->cached.jwt_md = NULL; } if (c->cached.service_url != NULL) { gpr_free(c->cached.service_url); c->cached.service_url = NULL; } c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); } static void jwt_destruct(grpc_credentials *creds) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; grpc_auth_json_key_destruct(&c->key); jwt_reset_cache(c); gpr_mu_destroy(&c->cache_mu); } static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; } static int jwt_has_request_metadata_only(const grpc_credentials *creds) { return 1; } static void jwt_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); /* See if we can return a cached jwt. */ grpc_credentials_md_store *jwt_md = NULL; { gpr_mu_lock(&c->cache_mu); if (c->cached.service_url != NULL && strcmp(c->cached.service_url, service_url) == 0 && c->cached.jwt_md != NULL && (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now(GPR_CLOCK_REALTIME)), refresh_threshold) > 0)) { jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } if (jwt_md == NULL) { char *jwt = NULL; /* Generate a new jwt. */ gpr_mu_lock(&c->cache_mu); jwt_reset_cache(c); jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL); if (jwt != NULL) { char *md_value; gpr_asprintf(&md_value, "Bearer %s", jwt); gpr_free(jwt); c->cached.jwt_expiration = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime); c->cached.service_url = gpr_strdup(service_url); c->cached.jwt_md = grpc_credentials_md_store_create(1); grpc_credentials_md_store_add_cstrings( c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value); gpr_free(md_value); jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } if (jwt_md != NULL) { cb(user_data, jwt_md->entries, jwt_md->num_entries, GRPC_CREDENTIALS_OK); grpc_credentials_md_store_unref(jwt_md); } else { cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); } } static grpc_credentials_vtable jwt_vtable = { jwt_destruct, jwt_has_request_metadata, jwt_has_request_metadata_only, jwt_get_request_metadata, NULL}; grpc_credentials * grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime) { grpc_service_account_jwt_access_credentials *c; if (!grpc_auth_json_key_is_valid(&key)) { gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); return NULL; } c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials)); memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_JWT; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &jwt_vtable; c->key = key; c->jwt_lifetime = token_lifetime; gpr_mu_init(&c->cache_mu); jwt_reset_cache(c); return &c->base; } grpc_credentials *grpc_service_account_jwt_access_credentials_create( const char *json_key, gpr_timespec token_lifetime, void *reserved) { GPR_ASSERT(reserved == NULL); return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key_create_from_string(json_key), token_lifetime); } /* -- Oauth2TokenFetcher credentials -- */ static void oauth2_token_fetcher_destruct(grpc_credentials *creds) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; grpc_credentials_md_store_unref(c->access_token_md); gpr_mu_destroy(&c->mu); grpc_httpcli_context_destroy(&c->httpcli_context); } static int oauth2_token_fetcher_has_request_metadata( const grpc_credentials *creds) { return 1; } static int oauth2_token_fetcher_has_request_metadata_only( const grpc_credentials *creds) { return 1; } grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( const grpc_httpcli_response *response, grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) { char *null_terminated_body = NULL; char *new_access_token = NULL; grpc_credentials_status status = GRPC_CREDENTIALS_OK; grpc_json *json = NULL; if (response == NULL) { gpr_log(GPR_ERROR, "Received NULL response."); status = GRPC_CREDENTIALS_ERROR; goto end; } if (response->body_length > 0) { null_terminated_body = gpr_malloc(response->body_length + 1); null_terminated_body[response->body_length] = '\0'; memcpy(null_terminated_body, response->body, response->body_length); } if (response->status != 200) { gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].", response->status, null_terminated_body != NULL ? null_terminated_body : ""); status = GRPC_CREDENTIALS_ERROR; goto end; } else { grpc_json *access_token = NULL; grpc_json *token_type = NULL; grpc_json *expires_in = NULL; grpc_json *ptr; json = grpc_json_parse_string(null_terminated_body); if (json == NULL) { gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body); status = GRPC_CREDENTIALS_ERROR; goto end; } if (json->type != GRPC_JSON_OBJECT) { gpr_log(GPR_ERROR, "Response should be a JSON object"); status = GRPC_CREDENTIALS_ERROR; goto end; } for (ptr = json->child; ptr; ptr = ptr->next) { if (strcmp(ptr->key, "access_token") == 0) { access_token = ptr; } else if (strcmp(ptr->key, "token_type") == 0) { token_type = ptr; } else if (strcmp(ptr->key, "expires_in") == 0) { expires_in = ptr; } } if (access_token == NULL || access_token->type != GRPC_JSON_STRING) { gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON."); status = GRPC_CREDENTIALS_ERROR; goto end; } if (token_type == NULL || token_type->type != GRPC_JSON_STRING) { gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON."); status = GRPC_CREDENTIALS_ERROR; goto end; } if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) { gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON."); status = GRPC_CREDENTIALS_ERROR; goto end; } gpr_asprintf(&new_access_token, "%s %s", token_type->value, access_token->value); token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); token_lifetime->tv_nsec = 0; token_lifetime->clock_type = GPR_TIMESPAN; if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md); *token_md = grpc_credentials_md_store_create(1); grpc_credentials_md_store_add_cstrings( *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); status = GRPC_CREDENTIALS_OK; } end: if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) { grpc_credentials_md_store_unref(*token_md); *token_md = NULL; } if (null_terminated_body != NULL) gpr_free(null_terminated_body); if (new_access_token != NULL) gpr_free(new_access_token); if (json != NULL) grpc_json_destroy(json); return status; } static void on_oauth2_token_fetcher_http_response( void *user_data, const grpc_httpcli_response *response) { grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)r->creds; gpr_timespec token_lifetime; grpc_credentials_status status; gpr_mu_lock(&c->mu); status = grpc_oauth2_token_fetcher_credentials_parse_server_response( response, &c->access_token_md, &token_lifetime); if (status == GRPC_CREDENTIALS_OK) { c->token_expiration = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime); r->cb(r->user_data, c->access_token_md->entries, c->access_token_md->num_entries, status); } else { c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); r->cb(r->user_data, NULL, 0, status); } gpr_mu_unlock(&c->mu); grpc_credentials_metadata_request_destroy(r); } static void oauth2_token_fetcher_get_request_metadata( grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); grpc_credentials_md_store *cached_access_token_md = NULL; { gpr_mu_lock(&c->mu); if (c->access_token_md != NULL && (gpr_time_cmp( gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), refresh_threshold) > 0)) { cached_access_token_md = grpc_credentials_md_store_ref(c->access_token_md); } gpr_mu_unlock(&c->mu); } if (cached_access_token_md != NULL) { cb(user_data, cached_access_token_md->entries, cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK); grpc_credentials_md_store_unref(cached_access_token_md); } else { c->fetch_func( grpc_credentials_metadata_request_create(creds, cb, user_data), &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold)); } } static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, grpc_fetch_oauth2_func fetch_func) { memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; gpr_ref_init(&c->base.refcount, 1); gpr_mu_init(&c->mu); c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); c->fetch_func = fetch_func; grpc_httpcli_context_init(&c->httpcli_context); } /* -- GoogleComputeEngine credentials. -- */ static grpc_credentials_vtable compute_engine_vtable = { oauth2_token_fetcher_destruct, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_get_request_metadata, NULL}; static void compute_engine_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { grpc_httpcli_header header = {"Metadata-Flavor", "Google"}; grpc_httpcli_request request; memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST; request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; request.hdr_count = 1; request.hdrs = &header; grpc_httpcli_get(httpcli_context, pollset, &request, deadline, response_cb, metadata_req); } grpc_credentials *grpc_google_compute_engine_credentials_create( void *reserved) { grpc_oauth2_token_fetcher_credentials *c = gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)); GPR_ASSERT(reserved == NULL); init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2); c->base.vtable = &compute_engine_vtable; return &c->base; } /* -- GoogleRefreshToken credentials. -- */ static void refresh_token_destruct(grpc_credentials *creds) { grpc_google_refresh_token_credentials *c = (grpc_google_refresh_token_credentials *)creds; grpc_auth_refresh_token_destruct(&c->refresh_token); oauth2_token_fetcher_destruct(&c->base.base); } static grpc_credentials_vtable refresh_token_vtable = { refresh_token_destruct, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_get_request_metadata, NULL}; static void refresh_token_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { grpc_google_refresh_token_credentials *c = (grpc_google_refresh_token_credentials *)metadata_req->creds; grpc_httpcli_header header = {"Content-Type", "application/x-www-form-urlencoded"}; grpc_httpcli_request request; char *body = NULL; gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, c->refresh_token.client_id, c->refresh_token.client_secret, c->refresh_token.refresh_token); memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST; request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; request.hdr_count = 1; request.hdrs = &header; request.handshaker = &grpc_httpcli_ssl; grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body), deadline, response_cb, metadata_req); gpr_free(body); } grpc_credentials * grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token refresh_token) { grpc_google_refresh_token_credentials *c; if (!grpc_auth_refresh_token_is_valid(&refresh_token)) { gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation"); return NULL; } c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials)); memset(c, 0, sizeof(grpc_google_refresh_token_credentials)); init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2); c->base.base.vtable = &refresh_token_vtable; c->refresh_token = refresh_token; return &c->base.base; } grpc_credentials *grpc_google_refresh_token_credentials_create( const char *json_refresh_token, void *reserved) { GPR_ASSERT(reserved == NULL); return grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token_create_from_string(json_refresh_token)); } /* -- Metadata-only credentials. -- */ static void md_only_test_destruct(grpc_credentials *creds) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; grpc_credentials_md_store_unref(c->md_store); } static int md_only_test_has_request_metadata(const grpc_credentials *creds) { return 1; } static int md_only_test_has_request_metadata_only( const grpc_credentials *creds) { return 1; } void on_simulated_token_fetch_done(void *user_data, int success) { grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; GPR_ASSERT(success); r->cb(r->user_data, c->md_store->entries, c->md_store->num_entries, GRPC_CREDENTIALS_OK); grpc_credentials_metadata_request_destroy(r); } static void md_only_test_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; if (c->is_async) { grpc_credentials_metadata_request *cb_arg = grpc_credentials_metadata_request_create(creds, cb, user_data); grpc_iomgr_closure_init(cb_arg->on_simulated_token_fetch_done_closure, on_simulated_token_fetch_done, cb_arg); grpc_iomgr_add_callback(cb_arg->on_simulated_token_fetch_done_closure); } else { cb(user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK); } } static grpc_credentials_vtable md_only_test_vtable = { md_only_test_destruct, md_only_test_has_request_metadata, md_only_test_has_request_metadata_only, md_only_test_get_request_metadata, NULL}; grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, const char *md_value, int is_async) { grpc_md_only_test_credentials *c = gpr_malloc(sizeof(grpc_md_only_test_credentials)); memset(c, 0, sizeof(grpc_md_only_test_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &md_only_test_vtable; gpr_ref_init(&c->base.refcount, 1); c->md_store = grpc_credentials_md_store_create(1); grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); c->is_async = is_async; return &c->base; } /* -- Oauth2 Access Token credentials. -- */ static void access_token_destruct(grpc_credentials *creds) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; grpc_credentials_md_store_unref(c->access_token_md); } static int access_token_has_request_metadata(const grpc_credentials *creds) { return 1; } static int access_token_has_request_metadata_only( const grpc_credentials *creds) { return 1; } static void access_token_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); } static grpc_credentials_vtable access_token_vtable = { access_token_destruct, access_token_has_request_metadata, access_token_has_request_metadata_only, access_token_get_request_metadata, NULL}; grpc_credentials *grpc_access_token_credentials_create(const char *access_token, void *reserved) { grpc_access_token_credentials *c = gpr_malloc(sizeof(grpc_access_token_credentials)); char *token_md_value; GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_access_token_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &access_token_vtable; gpr_ref_init(&c->base.refcount, 1); c->access_token_md = grpc_credentials_md_store_create(1); gpr_asprintf(&token_md_value, "Bearer %s", access_token); grpc_credentials_md_store_add_cstrings( c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); gpr_free(token_md_value); return &c->base; } /* -- Fake transport security credentials. -- */ static void fake_transport_security_credentials_destruct( grpc_credentials *creds) { /* Nothing to do here. */ } static void fake_transport_security_server_credentials_destruct( grpc_server_credentials *creds) { /* Nothing to do here. */ } static int fake_transport_security_has_request_metadata( const grpc_credentials *creds) { return 0; } static int fake_transport_security_has_request_metadata_only( const grpc_credentials *creds) { return 0; } static grpc_security_status fake_transport_security_create_security_connector( grpc_credentials *c, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1); return GRPC_SECURITY_OK; } static grpc_security_status fake_transport_security_server_create_security_connector( grpc_server_credentials *c, grpc_security_connector **sc) { *sc = grpc_fake_server_security_connector_create(); return GRPC_SECURITY_OK; } static grpc_credentials_vtable fake_transport_security_credentials_vtable = { fake_transport_security_credentials_destruct, fake_transport_security_has_request_metadata, fake_transport_security_has_request_metadata_only, NULL, fake_transport_security_create_security_connector}; static grpc_server_credentials_vtable fake_transport_security_server_credentials_vtable = { fake_transport_security_server_credentials_destruct, fake_transport_security_server_create_security_connector}; grpc_credentials *grpc_fake_transport_security_credentials_create(void) { grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials)); memset(c, 0, sizeof(grpc_credentials)); c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; c->vtable = &fake_transport_security_credentials_vtable; gpr_ref_init(&c->refcount, 1); return c; } grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( void) { grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials)); memset(c, 0, sizeof(grpc_server_credentials)); c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; gpr_ref_init(&c->refcount, 1); c->vtable = &fake_transport_security_server_credentials_vtable; return c; } /* -- Composite credentials. -- */ typedef struct { grpc_composite_credentials *composite_creds; size_t creds_index; grpc_credentials_md_store *md_elems; char *service_url; void *user_data; grpc_pollset *pollset; grpc_credentials_metadata_cb cb; } grpc_composite_credentials_metadata_context; static void composite_destruct(grpc_credentials *creds) { grpc_composite_credentials *c = (grpc_composite_credentials *)creds; size_t i; for (i = 0; i < c->inner.num_creds; i++) { grpc_credentials_unref(c->inner.creds_array[i]); } gpr_free(c->inner.creds_array); } static int composite_has_request_metadata(const grpc_credentials *creds) { const grpc_composite_credentials *c = (const grpc_composite_credentials *)creds; size_t i; for (i = 0; i < c->inner.num_creds; i++) { if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) { return 1; } } return 0; } static int composite_has_request_metadata_only(const grpc_credentials *creds) { const grpc_composite_credentials *c = (const grpc_composite_credentials *)creds; size_t i; for (i = 0; i < c->inner.num_creds; i++) { if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) { return 0; } } return 1; } static void composite_md_context_destroy( grpc_composite_credentials_metadata_context *ctx) { grpc_credentials_md_store_unref(ctx->md_elems); if (ctx->service_url != NULL) gpr_free(ctx->service_url); gpr_free(ctx); } static void composite_metadata_cb(void *user_data, grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { grpc_composite_credentials_metadata_context *ctx = (grpc_composite_credentials_metadata_context *)user_data; if (status != GRPC_CREDENTIALS_OK) { ctx->cb(ctx->user_data, NULL, 0, status); return; } /* Copy the metadata in the context. */ if (num_md > 0) { size_t i; for (i = 0; i < num_md; i++) { grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key, md_elems[i].value); } } /* See if we need to get some more metadata. */ while (ctx->creds_index < ctx->composite_creds->inner.num_creds) { grpc_credentials *inner_creds = ctx->composite_creds->inner.creds_array[ctx->creds_index++]; if (grpc_credentials_has_request_metadata(inner_creds)) { grpc_credentials_get_request_metadata(inner_creds, ctx->pollset, ctx->service_url, composite_metadata_cb, ctx); return; } } /* We're done!. */ ctx->cb(ctx->user_data, ctx->md_elems->entries, ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK); composite_md_context_destroy(ctx); } static void composite_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_composite_credentials *c = (grpc_composite_credentials *)creds; grpc_composite_credentials_metadata_context *ctx; if (!grpc_credentials_has_request_metadata(creds)) { cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK); return; } ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context)); memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context)); ctx->service_url = gpr_strdup(service_url); ctx->user_data = user_data; ctx->cb = cb; ctx->composite_creds = c; ctx->pollset = pollset; ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); while (ctx->creds_index < c->inner.num_creds) { grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++]; if (grpc_credentials_has_request_metadata(inner_creds)) { grpc_credentials_get_request_metadata(inner_creds, pollset, service_url, composite_metadata_cb, ctx); return; } } GPR_ASSERT(0); /* Should have exited before. */ } static grpc_security_status composite_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { grpc_composite_credentials *c = (grpc_composite_credentials *)creds; if (c->connector_creds == NULL) { gpr_log(GPR_ERROR, "Cannot create security connector, missing connector credentials."); return GRPC_SECURITY_ERROR; } return grpc_credentials_create_security_connector(c->connector_creds, target, args, creds, sc, new_args); } static grpc_credentials_vtable composite_credentials_vtable = { composite_destruct, composite_has_request_metadata, composite_has_request_metadata_only, composite_get_request_metadata, composite_create_security_connector}; static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { grpc_credentials_array result; grpc_credentials *creds = *creds_addr; result.creds_array = creds_addr; result.num_creds = 1; if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) { result = *grpc_composite_credentials_get_credentials(creds); } return result; } grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, grpc_credentials *creds2, void *reserved) { size_t i; size_t creds_array_byte_size; grpc_credentials_array creds1_array; grpc_credentials_array creds2_array; grpc_composite_credentials *c; GPR_ASSERT(reserved == NULL); GPR_ASSERT(creds1 != NULL); GPR_ASSERT(creds2 != NULL); c = gpr_malloc(sizeof(grpc_composite_credentials)); memset(c, 0, sizeof(grpc_composite_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE; c->base.vtable = &composite_credentials_vtable; gpr_ref_init(&c->base.refcount, 1); creds1_array = get_creds_array(&creds1); creds2_array = get_creds_array(&creds2); c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *); c->inner.creds_array = gpr_malloc(creds_array_byte_size); memset(c->inner.creds_array, 0, creds_array_byte_size); for (i = 0; i < creds1_array.num_creds; i++) { grpc_credentials *cur_creds = creds1_array.creds_array[i]; if (!grpc_credentials_has_request_metadata_only(cur_creds)) { if (c->connector_creds == NULL) { c->connector_creds = cur_creds; } else { gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials."); goto fail; } } c->inner.creds_array[i] = grpc_credentials_ref(cur_creds); } for (i = 0; i < creds2_array.num_creds; i++) { grpc_credentials *cur_creds = creds2_array.creds_array[i]; if (!grpc_credentials_has_request_metadata_only(cur_creds)) { if (c->connector_creds == NULL) { c->connector_creds = cur_creds; } else { gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials."); goto fail; } } c->inner.creds_array[i + creds1_array.num_creds] = grpc_credentials_ref(cur_creds); } return &c->base; fail: grpc_credentials_unref(&c->base); return NULL; } const grpc_credentials_array *grpc_composite_credentials_get_credentials( grpc_credentials *creds) { const grpc_composite_credentials *c = (const grpc_composite_credentials *)creds; GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0); return &c->inner; } grpc_credentials *grpc_credentials_contains_type( grpc_credentials *creds, const char *type, grpc_credentials **composite_creds) { size_t i; if (strcmp(creds->type, type) == 0) { if (composite_creds != NULL) *composite_creds = NULL; return creds; } else if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) { const grpc_credentials_array *inner_creds_array = grpc_composite_credentials_get_credentials(creds); for (i = 0; i < inner_creds_array->num_creds; i++) { if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) { if (composite_creds != NULL) *composite_creds = creds; return inner_creds_array->creds_array[i]; } } } return NULL; } /* -- IAM credentials. -- */ static void iam_destruct(grpc_credentials *creds) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; grpc_credentials_md_store_unref(c->iam_md); } static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; } static int iam_has_request_metadata_only(const grpc_credentials *creds) { return 1; } static void iam_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; cb(user_data, c->iam_md->entries, c->iam_md->num_entries, GRPC_CREDENTIALS_OK); } static grpc_credentials_vtable iam_vtable = { iam_destruct, iam_has_request_metadata, iam_has_request_metadata_only, iam_get_request_metadata, NULL}; grpc_credentials *grpc_google_iam_credentials_create( const char *token, const char *authority_selector, void *reserved) { grpc_google_iam_credentials *c; GPR_ASSERT(reserved == NULL); GPR_ASSERT(token != NULL); GPR_ASSERT(authority_selector != NULL); c = gpr_malloc(sizeof(grpc_google_iam_credentials)); memset(c, 0, sizeof(grpc_google_iam_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_IAM; c->base.vtable = &iam_vtable; gpr_ref_init(&c->base.refcount, 1); c->iam_md = grpc_credentials_md_store_create(2); grpc_credentials_md_store_add_cstrings( c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); grpc_credentials_md_store_add_cstrings( c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); return &c->base; } grpc-0.11.1/src/core/security/security_context.c0000644000175000017500000002571312600663151022074 0ustar apollockapollock/* * * 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 #include "src/core/security/security_context.h" #include "src/core/surface/call.h" #include "src/core/support/string.h" #include #include #include #include /* --- grpc_call --- */ grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_credentials *creds) { grpc_client_security_context *ctx = NULL; if (!grpc_call_is_client(call)) { gpr_log(GPR_ERROR, "Method is client-side only."); return GRPC_CALL_ERROR_NOT_ON_SERVER; } if (creds != NULL && !grpc_credentials_has_request_metadata_only(creds)) { gpr_log(GPR_ERROR, "Incompatible credentials to set on a call."); return GRPC_CALL_ERROR; } ctx = (grpc_client_security_context *)grpc_call_context_get( call, GRPC_CONTEXT_SECURITY); if (ctx == NULL) { ctx = grpc_client_security_context_create(); ctx->creds = grpc_credentials_ref(creds); grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, grpc_client_security_context_destroy); } else { grpc_credentials_unref(ctx->creds); ctx->creds = grpc_credentials_ref(creds); } return GRPC_CALL_OK; } grpc_auth_context *grpc_call_auth_context(grpc_call *call) { void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY); if (sec_ctx == NULL) return NULL; return grpc_call_is_client(call) ? GRPC_AUTH_CONTEXT_REF( ((grpc_client_security_context *)sec_ctx)->auth_context, "grpc_call_auth_context client") : GRPC_AUTH_CONTEXT_REF( ((grpc_server_security_context *)sec_ctx)->auth_context, "grpc_call_auth_context server"); } void grpc_auth_context_release(grpc_auth_context *context) { GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref"); } /* --- grpc_client_security_context --- */ grpc_client_security_context *grpc_client_security_context_create(void) { grpc_client_security_context *ctx = gpr_malloc(sizeof(grpc_client_security_context)); memset(ctx, 0, sizeof(grpc_client_security_context)); return ctx; } void grpc_client_security_context_destroy(void *ctx) { grpc_client_security_context *c = (grpc_client_security_context *)ctx; grpc_credentials_unref(c->creds); GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); gpr_free(ctx); } /* --- grpc_server_security_context --- */ grpc_server_security_context *grpc_server_security_context_create(void) { grpc_server_security_context *ctx = gpr_malloc(sizeof(grpc_server_security_context)); memset(ctx, 0, sizeof(grpc_server_security_context)); return ctx; } void grpc_server_security_context_destroy(void *ctx) { grpc_server_security_context *c = (grpc_server_security_context *)ctx; GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context"); gpr_free(ctx); } /* --- grpc_auth_context --- */ static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); memset(ctx, 0, sizeof(grpc_auth_context)); gpr_ref_init(&ctx->refcount, 1); if (chained != NULL) { ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); ctx->peer_identity_property_name = ctx->chained->peer_identity_property_name; } return ctx; } #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx, const char *file, int line, const char *reason) { if (ctx == NULL) return NULL; gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "AUTH_CONTEXT:%p ref %d -> %d %s", ctx, (int)ctx->refcount.count, (int)ctx->refcount.count + 1, reason); #else grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) { if (ctx == NULL) return NULL; #endif gpr_ref(&ctx->refcount); return ctx; } #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG void grpc_auth_context_unref(grpc_auth_context *ctx, const char *file, int line, const char *reason) { if (ctx == NULL) return; gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "AUTH_CONTEXT:%p unref %d -> %d %s", ctx, (int)ctx->refcount.count, (int)ctx->refcount.count - 1, reason); #else void grpc_auth_context_unref(grpc_auth_context *ctx) { if (ctx == NULL) return; #endif if (gpr_unref(&ctx->refcount)) { size_t i; GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); if (ctx->properties.array != NULL) { for (i = 0; i < ctx->properties.count; i++) { grpc_auth_property_reset(&ctx->properties.array[i]); } gpr_free(ctx->properties.array); } gpr_free(ctx); } } const char *grpc_auth_context_peer_identity_property_name( const grpc_auth_context *ctx) { return ctx->peer_identity_property_name; } int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, const char *name) { grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(ctx, name); const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); if (prop == NULL) { gpr_log(GPR_ERROR, "Property name %s not found in auth context.", name != NULL ? name : "NULL"); return 0; } ctx->peer_identity_property_name = prop->name; return 1; } int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) { return ctx->peer_identity_property_name == NULL ? 0 : 1; } grpc_auth_property_iterator grpc_auth_context_property_iterator( const grpc_auth_context *ctx) { grpc_auth_property_iterator it = empty_iterator; if (ctx == NULL) return it; it.ctx = ctx; return it; } const grpc_auth_property *grpc_auth_property_iterator_next( grpc_auth_property_iterator *it) { if (it == NULL || it->ctx == NULL) return NULL; while (it->index == it->ctx->properties.count) { if (it->ctx->chained == NULL) return NULL; it->ctx = it->ctx->chained; it->index = 0; } if (it->name == NULL) { return &it->ctx->properties.array[it->index++]; } else { while (it->index < it->ctx->properties.count) { const grpc_auth_property *prop = &it->ctx->properties.array[it->index++]; GPR_ASSERT(prop->name != NULL); if (strcmp(it->name, prop->name) == 0) { return prop; } } /* We could not find the name, try another round. */ return grpc_auth_property_iterator_next(it); } } grpc_auth_property_iterator grpc_auth_context_find_properties_by_name( const grpc_auth_context *ctx, const char *name) { grpc_auth_property_iterator it = empty_iterator; if (ctx == NULL || name == NULL) return empty_iterator; it.ctx = ctx; it.name = name; return it; } grpc_auth_property_iterator grpc_auth_context_peer_identity( const grpc_auth_context *ctx) { if (ctx == NULL) return empty_iterator; return grpc_auth_context_find_properties_by_name( ctx, ctx->peer_identity_property_name); } static void ensure_auth_context_capacity(grpc_auth_context *ctx) { if (ctx->properties.count == ctx->properties.capacity) { ctx->properties.capacity = GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2); ctx->properties.array = gpr_realloc(ctx->properties.array, ctx->properties.capacity * sizeof(grpc_auth_property)); } } void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, const char *value, size_t value_length) { grpc_auth_property *prop; ensure_auth_context_capacity(ctx); prop = &ctx->properties.array[ctx->properties.count++]; prop->name = gpr_strdup(name); prop->value = gpr_malloc(value_length + 1); memcpy(prop->value, value, value_length); prop->value[value_length] = '\0'; prop->value_length = value_length; } void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, const char *name, const char *value) { grpc_auth_property *prop; ensure_auth_context_capacity(ctx); prop = &ctx->properties.array[ctx->properties.count++]; prop->name = gpr_strdup(name); prop->value = gpr_strdup(value); prop->value_length = strlen(value); } void grpc_auth_property_reset(grpc_auth_property *property) { gpr_free(property->name); gpr_free(property->value); memset(property, 0, sizeof(grpc_auth_property)); } grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p) { grpc_arg arg; memset(&arg, 0, sizeof(grpc_arg)); arg.type = GRPC_ARG_POINTER; arg.key = GRPC_AUTH_METADATA_PROCESSOR_ARG; arg.value.pointer.p = p; return arg; } grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( const grpc_arg *arg) { if (strcmp(arg->key, GRPC_AUTH_METADATA_PROCESSOR_ARG) != 0) return NULL; if (arg->type != GRPC_ARG_POINTER) { gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, GRPC_AUTH_METADATA_PROCESSOR_ARG); return NULL; } return arg->value.pointer.p; } grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( const grpc_channel_args *args) { size_t i; if (args == NULL) return NULL; for (i = 0; i < args->num_args; i++) { grpc_auth_metadata_processor *p = grpc_auth_metadata_processor_from_arg(&args->args[i]); if (p != NULL) return p; } return NULL; } grpc-0.11.1/src/core/security/client_auth_filter.c0000644000175000017500000003234612600663151022325 0ustar apollockapollock/* * * 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/security/auth_filters.h" #include #include #include #include #include "src/core/support/string.h" #include "src/core/channel/channel_stack.h" #include "src/core/security/security_context.h" #include "src/core/security/security_connector.h" #include "src/core/security/credentials.h" #include "src/core/surface/call.h" #define MAX_CREDENTIALS_METADATA_COUNT 4 /* We can have a per-call credentials. */ typedef struct { grpc_credentials *creds; grpc_mdstr *host; grpc_mdstr *method; /* pollset bound to this call; if we need to make external network requests, they should be done under this pollset so that work can progress when this call wants work to progress */ grpc_pollset *pollset; grpc_transport_stream_op op; size_t op_md_idx; int sent_initial_metadata; gpr_uint8 security_context_set; grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; } call_data; /* We can have a per-channel credentials. */ typedef struct { grpc_channel_security_connector *security_connector; grpc_mdctx *md_ctx; grpc_mdstr *authority_string; grpc_mdstr *path_string; grpc_mdstr *error_msg_key; grpc_mdstr *status_key; } channel_data; static void bubble_up_error(grpc_call_element *elem, grpc_status_code status, const char *error_msg) { call_data *calld = elem->call_data; gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); grpc_transport_stream_op_add_cancellation(&calld->op, status); grpc_call_next_op(elem, &calld->op); } static void on_credentials_metadata(void *user_data, grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_transport_stream_op *op = &calld->op; grpc_metadata_batch *mdb; size_t i; if (status != GRPC_CREDENTIALS_OK) { bubble_up_error(elem, GRPC_STATUS_UNAUTHENTICATED, "Credentials failed to get metadata."); return; } GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); GPR_ASSERT(op->send_ops && op->send_ops->nops > calld->op_md_idx && op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA); mdb = &op->send_ops->ops[calld->op_md_idx].data.metadata; for (i = 0; i < num_md; i++) { grpc_metadata_batch_add_tail( mdb, &calld->md_links[i], grpc_mdelem_from_slices(chand->md_ctx, gpr_slice_ref(md_elems[i].key), gpr_slice_ref(md_elems[i].value))); } grpc_call_next_op(elem, op); } static char *build_service_url(const char *url_scheme, call_data *calld) { char *service_url; char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); char *last_slash = strrchr(service, '/'); if (last_slash == NULL) { gpr_log(GPR_ERROR, "No '/' found in fully qualified method name"); service[0] = '\0'; } else if (last_slash == service) { /* No service part in fully qualified method name: will just be "/". */ service[1] = '\0'; } else { *last_slash = '\0'; } if (url_scheme == NULL) url_scheme = ""; gpr_asprintf(&service_url, "%s://%s%s", url_scheme, grpc_mdstr_as_c_string(calld->host), service); gpr_free(service); return service_url; } static void send_security_metadata(grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; char *service_url = NULL; grpc_credentials *channel_creds = chand->security_connector->request_metadata_creds; int channel_creds_has_md = (channel_creds != NULL) && grpc_credentials_has_request_metadata(channel_creds); int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL) && grpc_credentials_has_request_metadata(ctx->creds); if (!channel_creds_has_md && !call_creds_has_md) { /* Skip sending metadata altogether. */ grpc_call_next_op(elem, op); return; } if (channel_creds_has_md && call_creds_has_md) { calld->creds = grpc_composite_credentials_create(channel_creds, ctx->creds, NULL); if (calld->creds == NULL) { bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, "Incompatible credentials set on channel and call."); return; } } else { calld->creds = grpc_credentials_ref(call_creds_has_md ? ctx->creds : channel_creds); } service_url = build_service_url(chand->security_connector->base.url_scheme, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ GPR_ASSERT(calld->pollset); grpc_credentials_get_request_metadata( calld->creds, calld->pollset, service_url, on_credentials_metadata, elem); gpr_free(service_url); } static void on_host_checked(void *user_data, grpc_security_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; if (status == GRPC_SECURITY_OK) { send_security_metadata(elem, &calld->op); } else { char *error_msg; gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", grpc_mdstr_as_c_string(calld->host)); bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg); gpr_free(error_msg); } } /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void auth_start_transport_op(grpc_call_element *elem, grpc_transport_stream_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_linked_mdelem *l; size_t i; grpc_client_security_context *sec_ctx = NULL; if (calld->security_context_set == 0 && op->cancel_with_status == GRPC_STATUS_OK) { calld->security_context_set = 1; GPR_ASSERT(op->context); if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) { op->context[GRPC_CONTEXT_SECURITY].value = grpc_client_security_context_create(); op->context[GRPC_CONTEXT_SECURITY].destroy = grpc_client_security_context_destroy; } sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value; GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); sec_ctx->auth_context = GRPC_AUTH_CONTEXT_REF( chand->security_connector->base.auth_context, "client_auth_filter"); } if (op->bind_pollset != NULL) { calld->pollset = op->bind_pollset; } if (op->send_ops != NULL && !calld->sent_initial_metadata) { size_t nops = op->send_ops->nops; grpc_stream_op *ops = op->send_ops->ops; for (i = 0; i < nops; i++) { grpc_stream_op *sop = &ops[i]; if (sop->type != GRPC_OP_METADATA) continue; calld->op_md_idx = i; calld->sent_initial_metadata = 1; for (l = sop->data.metadata.list.head; l != NULL; l = l->next) { grpc_mdelem *md = l->md; /* Pointer comparison is OK for md_elems created from the same context. */ if (md->key == chand->authority_string) { if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host); calld->host = GRPC_MDSTR_REF(md->value); } else if (md->key == chand->path_string) { if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method); calld->method = GRPC_MDSTR_REF(md->value); } } if (calld->host != NULL) { grpc_security_status status; const char *call_host = grpc_mdstr_as_c_string(calld->host); calld->op = *op; /* Copy op (originates from the caller's stack). */ status = grpc_channel_security_connector_check_call_host( chand->security_connector, call_host, on_host_checked, elem); if (status != GRPC_SECURITY_OK) { if (status == GRPC_SECURITY_ERROR) { char *error_msg; gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", call_host); bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg); gpr_free(error_msg); } return; /* early exit */ } } send_security_metadata(elem, op); return; /* early exit */ } } /* pass control up or down the stack */ grpc_call_next_op(elem, op); } /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { call_data *calld = elem->call_data; calld->creds = NULL; calld->host = NULL; calld->method = NULL; calld->pollset = NULL; calld->sent_initial_metadata = 0; calld->security_context_set = 0; GPR_ASSERT(!initial_op || !initial_op->send_ops); } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { call_data *calld = elem->call_data; grpc_credentials_unref(calld->creds); if (calld->host != NULL) { GRPC_MDSTR_UNREF(calld->host); } if (calld->method != NULL) { GRPC_MDSTR_UNREF(calld->method); } } /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *metadata_context, int is_first, int is_last) { grpc_security_connector *sc = grpc_find_security_connector_in_args(args); /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; /* The first and the last filters tend to be implemented differently to handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!is_last); GPR_ASSERT(sc != NULL); /* initialize members */ GPR_ASSERT(sc->is_client_side); chand->security_connector = (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF( sc, "client_auth_filter"); chand->md_ctx = metadata_context; chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0); chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0); chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0); chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0); } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; grpc_channel_security_connector *ctx = chand->security_connector; if (ctx != NULL) GRPC_SECURITY_CONNECTOR_UNREF(&ctx->base, "client_auth_filter"); if (chand->authority_string != NULL) { GRPC_MDSTR_UNREF(chand->authority_string); } if (chand->error_msg_key != NULL) { GRPC_MDSTR_UNREF(chand->error_msg_key); } if (chand->status_key != NULL) { GRPC_MDSTR_UNREF(chand->status_key); } if (chand->path_string != NULL) { GRPC_MDSTR_UNREF(chand->path_string); } } const grpc_channel_filter grpc_client_auth_filter = { auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, "client-auth"}; grpc-0.11.1/src/core/profiling/0000755000175000017500000000000012600663151016427 5ustar apollockapollockgrpc-0.11.1/src/core/profiling/stap_probes.d0000644000175000017500000000022312600663151021112 0ustar apollockapollockprovider _stap { probe add_mark(int tag); probe add_important_mark(int tag); probe timing_ns_begin(int tag); probe timing_ns_end(int tag); }; grpc-0.11.1/src/core/profiling/stap_timers.c0000644000175000017500000000465712600663151021141 0ustar apollockapollock/* * * 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 #ifdef GRPC_STAP_PROFILER #include "src/core/profiling/timers.h" #include /* Generated from src/core/profiling/stap_probes.d */ #include "src/core/profiling/stap_probes.h" /* Latency profiler API implementation. */ void grpc_timer_add_mark(int tag, const char* tagstr, void* id, const char* file, int line) { _STAP_ADD_MARK(tag); } void grpc_timer_add_important_mark(int tag, const char* tagstr, void* id, const char* file, int line) { _STAP_ADD_IMPORTANT_MARK(tag); } void grpc_timer_begin(int tag, const char* tagstr, void* id, const char* file, int line) { _STAP_TIMING_NS_BEGIN(tag); } void grpc_timer_end(int tag, const char* tagstr, void* id, const char* file, int line) { _STAP_TIMING_NS_END(tag); } #endif /* GRPC_STAP_PROFILER */ grpc-0.11.1/src/core/profiling/timers.h0000644000175000017500000001303012600663151020100 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_CORE_PROFILING_TIMERS_H #define GRPC_CORE_PROFILING_TIMERS_H #ifdef __cplusplus extern "C" { #endif void grpc_timers_global_init(void); void grpc_timers_global_destroy(void); void grpc_timer_add_mark(int tag, const char *tagstr, void *id, const char *file, int line); void grpc_timer_add_important_mark(int tag, const char *tagstr, void *id, const char *file, int line); void grpc_timer_begin(int tag, const char *tagstr, void *id, const char *file, int line); void grpc_timer_end(int tag, const char *tagstr, void *id, const char *file, int line); enum grpc_profiling_tags { /* Any GRPC_PTAG_* >= than the threshold won't generate any profiling mark. */ GRPC_PTAG_IGNORE_THRESHOLD = 1000000, /* Re. Protos. */ GRPC_PTAG_PROTO_SERIALIZE = 100 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_PROTO_DESERIALIZE = 101 + GRPC_PTAG_IGNORE_THRESHOLD, /* Re. sockets. */ GRPC_PTAG_HANDLE_READ = 200 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_SENDMSG = 201 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_RECVMSG = 202 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_POLL_FINISHED = 203 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_TCP_CB_WRITE = 204 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_TCP_WRITE = 205 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_CALL_ON_DONE_RECV = 206 + GRPC_PTAG_IGNORE_THRESHOLD, /* C++ */ GRPC_PTAG_CPP_CALL_CREATED = 300 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_CPP_PERFORM_OPS = 301 + GRPC_PTAG_IGNORE_THRESHOLD, /* Transports */ GRPC_PTAG_HTTP2_UNLOCK = 401 + GRPC_PTAG_IGNORE_THRESHOLD, GRPC_PTAG_HTTP2_UNLOCK_CLEANUP = 402 + GRPC_PTAG_IGNORE_THRESHOLD, /* > 1024 Unassigned reserved. For any miscellaneous use. * Use addition to generate tags from this base or take advantage of the 10 * zero'd bits for OR-ing. */ GRPC_PTAG_OTHER_BASE = 1024 }; #if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER)) /* No profiling. No-op all the things. */ #define GRPC_TIMER_MARK(tag, id) \ do { \ } while (0) #define GRPC_TIMER_IMPORTANT_MARK(tag, id) \ do { \ } while (0) #define GRPC_TIMER_BEGIN(tag, id) \ do { \ } while (0) #define GRPC_TIMER_END(tag, id) \ do { \ } while (0) #else /* at least one profiler requested... */ /* ... hopefully only one. */ #if defined(GRPC_STAP_PROFILER) && defined(GRPC_BASIC_PROFILER) #error "GRPC_STAP_PROFILER and GRPC_BASIC_PROFILER are mutually exclusive." #endif /* Generic profiling interface. */ #define GRPC_TIMER_MARK(tag, id) \ if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \ grpc_timer_add_mark(tag, #tag, ((void *)(gpr_intptr)(id)), __FILE__, \ __LINE__); \ } #define GRPC_TIMER_IMPORTANT_MARK(tag, id) \ if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \ grpc_timer_add_important_mark(tag, #tag, ((void *)(gpr_intptr)(id)), \ __FILE__, __LINE__); \ } #define GRPC_TIMER_BEGIN(tag, id) \ if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \ grpc_timer_begin(tag, #tag, ((void *)(gpr_intptr)(id)), __FILE__, \ __LINE__); \ } #define GRPC_TIMER_END(tag, id) \ if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \ grpc_timer_end(tag, #tag, ((void *)(gpr_intptr)(id)), __FILE__, __LINE__); \ } #ifdef GRPC_STAP_PROFILER /* Empty placeholder for now. */ #endif /* GRPC_STAP_PROFILER */ #ifdef GRPC_BASIC_PROFILER /* Empty placeholder for now. */ #endif /* GRPC_BASIC_PROFILER */ #endif /* at least one profiler requested. */ #ifdef __cplusplus } #endif #endif /* GRPC_CORE_PROFILING_TIMERS_H */ grpc-0.11.1/src/core/profiling/basic_timers.c0000644000175000017500000001042312600663151021237 0ustar apollockapollock/* * * 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 #ifdef GRPC_BASIC_PROFILER #include "src/core/profiling/timers.h" #include #include #include #include #include #include typedef enum { BEGIN = '{', END = '}', MARK = '.', IMPORTANT = '!' } marker_type; typedef struct grpc_timer_entry { gpr_timespec tm; int tag; const char* tagstr; marker_type type; void* id; const char* file; int line; } grpc_timer_entry; #define MAX_COUNT (1024 * 1024 / sizeof(grpc_timer_entry)) static __thread grpc_timer_entry log[MAX_COUNT]; static __thread int count; static void log_report() { int i; for (i = 0; i < count; i++) { grpc_timer_entry* entry = &(log[i]); printf("GRPC_LAT_PROF %ld.%09d %p %c %d(%s) %p %s %d\n", entry->tm.tv_sec, entry->tm.tv_nsec, (void*)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tag, entry->tagstr, entry->id, entry->file, entry->line); } /* Now clear out the log */ count = 0; } static void grpc_timers_log_add(int tag, const char* tagstr, marker_type type, void* id, const char* file, int line) { grpc_timer_entry* entry; /* TODO (vpai) : Improve concurrency */ if (count == MAX_COUNT) { log_report(); } entry = &log[count++]; entry->tm = gpr_now(GPR_CLOCK_PRECISE); entry->tag = tag; entry->tagstr = tagstr; entry->type = type; entry->id = id; entry->file = file; entry->line = line; } /* Latency profiler API implementation. */ void grpc_timer_add_mark(int tag, const char* tagstr, void* id, const char* file, int line) { if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { grpc_timers_log_add(tag, tagstr, MARK, id, file, line); } } void grpc_timer_add_important_mark(int tag, const char* tagstr, void* id, const char* file, int line) { if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { grpc_timers_log_add(tag, tagstr, IMPORTANT, id, file, line); } } void grpc_timer_begin(int tag, const char* tagstr, void* id, const char* file, int line) { if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { grpc_timers_log_add(tag, tagstr, BEGIN, id, file, line); } } void grpc_timer_end(int tag, const char* tagstr, void* id, const char* file, int line) { if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { grpc_timers_log_add(tag, tagstr, END, id, file, line); } } /* Basic profiler specific API functions. */ void grpc_timers_global_init(void) {} void grpc_timers_global_destroy(void) {} #else /* !GRPC_BASIC_PROFILER */ void grpc_timers_global_init(void) {} void grpc_timers_global_destroy(void) {} #endif /* GRPC_BASIC_PROFILER */ grpc-0.11.1/src/core/iomgr/0000755000175000017500000000000012600663151015553 5ustar apollockapollockgrpc-0.11.1/src/core/iomgr/time_averaged_stats.c0000644000175000017500000000631212600663151021733 0ustar apollockapollock/* * * 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/iomgr/time_averaged_stats.h" void grpc_time_averaged_stats_init(grpc_time_averaged_stats *stats, double init_avg, double regress_weight, double persistence_factor) { stats->init_avg = init_avg; stats->regress_weight = regress_weight; stats->persistence_factor = persistence_factor; stats->batch_total_value = 0; stats->batch_num_samples = 0; stats->aggregate_total_weight = 0; stats->aggregate_weighted_avg = init_avg; } void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats *stats, double value) { stats->batch_total_value += value; ++stats->batch_num_samples; } double grpc_time_averaged_stats_update_average( grpc_time_averaged_stats *stats) { /* Start with the current batch: */ double weighted_sum = stats->batch_total_value; double total_weight = stats->batch_num_samples; if (stats->regress_weight > 0) { /* Add in the regression towards init_avg_: */ weighted_sum += stats->regress_weight * stats->init_avg; total_weight += stats->regress_weight; } if (stats->persistence_factor > 0) { /* Add in the persistence: */ const double prev_sample_weight = stats->persistence_factor * stats->aggregate_total_weight; weighted_sum += prev_sample_weight * stats->aggregate_weighted_avg; total_weight += prev_sample_weight; } stats->aggregate_weighted_avg = (total_weight > 0) ? (weighted_sum / total_weight) : stats->init_avg; stats->aggregate_total_weight = total_weight; stats->batch_num_samples = 0; stats->batch_total_value = 0; return stats->aggregate_weighted_avg; } grpc-0.11.1/src/core/iomgr/tcp_posix.c0000644000175000017500000003302012600663151017725 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/tcp_posix.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "src/core/support/string.h" #include "src/core/debug/trace.h" #include "src/core/profiling/timers.h" #ifdef GPR_HAVE_MSG_NOSIGNAL #define SENDMSG_FLAGS MSG_NOSIGNAL #else #define SENDMSG_FLAGS 0 #endif int grpc_tcp_trace = 0; typedef struct { grpc_endpoint base; grpc_fd *em_fd; int fd; int iov_size; /* Number of slices to allocate per read attempt */ int finished_edge; size_t slice_size; gpr_refcount refcount; gpr_slice_buffer *incoming_buffer; gpr_slice_buffer *outgoing_buffer; /** slice within outgoing_buffer to write next */ size_t outgoing_slice_idx; /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */ size_t outgoing_byte_idx; grpc_iomgr_closure *read_cb; grpc_iomgr_closure *write_cb; grpc_iomgr_closure read_closure; grpc_iomgr_closure write_closure; char *peer_string; } grpc_tcp; static void tcp_handle_read(void *arg /* grpc_tcp */, int success); static void tcp_handle_write(void *arg /* grpc_tcp */, int success); static void tcp_shutdown(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_fd_shutdown(tcp->em_fd); } static void tcp_free(grpc_tcp *tcp) { grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan"); gpr_free(tcp->peer_string); gpr_free(tcp); } /*#define GRPC_TCP_REFCOUNT_DEBUG*/ #ifdef GRPC_TCP_REFCOUNT_DEBUG #define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, reason, tcp->refcount.count, tcp->refcount.count - 1); if (gpr_unref(&tcp->refcount)) { tcp_free(tcp); } } static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, reason, tcp->refcount.count, tcp->refcount.count + 1); gpr_ref(&tcp->refcount); } #else #define TCP_UNREF(tcp, reason) tcp_unref((tcp)) #define TCP_REF(tcp, reason) tcp_ref((tcp)) static void tcp_unref(grpc_tcp *tcp) { if (gpr_unref(&tcp->refcount)) { tcp_free(tcp); } } static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } #endif static void tcp_destroy(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; TCP_UNREF(tcp, "destroy"); } static void call_read_cb(grpc_tcp *tcp, int success) { grpc_iomgr_closure *cb = tcp->read_cb; if (grpc_tcp_trace) { size_t i; gpr_log(GPR_DEBUG, "read: success=%d", success); for (i = 0; i < tcp->incoming_buffer->count; i++) { char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump); gpr_free(dump); } } tcp->read_cb = NULL; tcp->incoming_buffer = NULL; cb->cb(cb->cb_arg, success); } #define MAX_READ_IOVEC 4 static void tcp_continue_read(grpc_tcp *tcp) { struct msghdr msg; struct iovec iov[MAX_READ_IOVEC]; ssize_t read_bytes; size_t i; GPR_ASSERT(!tcp->finished_edge); GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC); GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC); GRPC_TIMER_BEGIN(GRPC_PTAG_HANDLE_READ, 0); while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) { gpr_slice_buffer_add_indexed(tcp->incoming_buffer, gpr_slice_malloc(tcp->slice_size)); } for (i = 0; i < tcp->incoming_buffer->count; i++) { iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); } msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = tcp->iov_size; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; GRPC_TIMER_BEGIN(GRPC_PTAG_RECVMSG, 0); do { read_bytes = recvmsg(tcp->fd, &msg, 0); } while (read_bytes < 0 && errno == EINTR); GRPC_TIMER_END(GRPC_PTAG_RECVMSG, 0); if (read_bytes < 0) { /* NB: After calling call_read_cb a parallel call of the read handler may * be running. */ if (errno == EAGAIN) { if (tcp->iov_size > 1) { tcp->iov_size /= 2; } /* We've consumed the edge, request a new one */ grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); } else { /* TODO(klempner): Log interesting errors */ gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); call_read_cb(tcp, 0); TCP_UNREF(tcp, "read"); } } else if (read_bytes == 0) { /* 0 read size ==> end of stream */ gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); call_read_cb(tcp, 0); TCP_UNREF(tcp, "read"); } else { GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); if ((size_t)read_bytes < tcp->incoming_buffer->length) { gpr_slice_buffer_trim_end(tcp->incoming_buffer, tcp->incoming_buffer->length - read_bytes); } else if (tcp->iov_size < MAX_READ_IOVEC) { ++tcp->iov_size; } GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length); call_read_cb(tcp, 1); TCP_UNREF(tcp, "read"); } GRPC_TIMER_END(GRPC_PTAG_HANDLE_READ, 0); } static void tcp_handle_read(void *arg /* grpc_tcp */, int success) { grpc_tcp *tcp = (grpc_tcp *)arg; GPR_ASSERT(!tcp->finished_edge); if (!success) { gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); call_read_cb(tcp, 0); TCP_UNREF(tcp, "read"); } else { tcp_continue_read(tcp); } } static grpc_endpoint_op_status tcp_read(grpc_endpoint *ep, gpr_slice_buffer *incoming_buffer, grpc_iomgr_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; tcp->incoming_buffer = incoming_buffer; gpr_slice_buffer_reset_and_unref(incoming_buffer); TCP_REF(tcp, "read"); if (tcp->finished_edge) { tcp->finished_edge = 0; grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); } else { grpc_iomgr_add_delayed_callback(&tcp->read_closure, 1); } /* TODO(ctiller): immediate return */ return GRPC_ENDPOINT_PENDING; } #define MAX_WRITE_IOVEC 16 static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) { struct msghdr msg; struct iovec iov[MAX_WRITE_IOVEC]; int iov_size; ssize_t sent_length; ssize_t sending_length; ssize_t trailing; ssize_t unwind_slice_idx; ssize_t unwind_byte_idx; for (;;) { sending_length = 0; unwind_slice_idx = tcp->outgoing_slice_idx; unwind_byte_idx = tcp->outgoing_byte_idx; for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count && iov_size != MAX_WRITE_IOVEC; iov_size++) { iov[iov_size].iov_base = GPR_SLICE_START_PTR( tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) + tcp->outgoing_byte_idx; iov[iov_size].iov_len = GPR_SLICE_LENGTH( tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) - tcp->outgoing_byte_idx; sending_length += iov[iov_size].iov_len; tcp->outgoing_slice_idx++; tcp->outgoing_byte_idx = 0; } GPR_ASSERT(iov_size > 0); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = iov_size; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; GRPC_TIMER_BEGIN(GRPC_PTAG_SENDMSG, 0); do { /* TODO(klempner): Cork if this is a partial write */ sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS); } while (sent_length < 0 && errno == EINTR); GRPC_TIMER_END(GRPC_PTAG_SENDMSG, 0); if (sent_length < 0) { if (errno == EAGAIN) { tcp->outgoing_slice_idx = unwind_slice_idx; tcp->outgoing_byte_idx = unwind_byte_idx; return GRPC_ENDPOINT_PENDING; } else { /* TODO(klempner): Log some of these */ return GRPC_ENDPOINT_ERROR; } } GPR_ASSERT(tcp->outgoing_byte_idx == 0); trailing = sending_length - sent_length; while (trailing > 0) { ssize_t slice_length; tcp->outgoing_slice_idx--; slice_length = GPR_SLICE_LENGTH( tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]); if (slice_length > trailing) { tcp->outgoing_byte_idx = slice_length - trailing; break; } else { trailing -= slice_length; } } if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) { return GRPC_ENDPOINT_DONE; } }; } static void tcp_handle_write(void *arg /* grpc_tcp */, int success) { grpc_tcp *tcp = (grpc_tcp *)arg; grpc_endpoint_op_status status; grpc_iomgr_closure *cb; if (!success) { cb = tcp->write_cb; tcp->write_cb = NULL; cb->cb(cb->cb_arg, 0); TCP_UNREF(tcp, "write"); return; } GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0); status = tcp_flush(tcp); if (status == GRPC_ENDPOINT_PENDING) { grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); } else { cb = tcp->write_cb; tcp->write_cb = NULL; cb->cb(cb->cb_arg, status == GRPC_ENDPOINT_DONE); TCP_UNREF(tcp, "write"); } GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0); } static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep, gpr_slice_buffer *buf, grpc_iomgr_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_endpoint_op_status status; if (grpc_tcp_trace) { size_t i; for (i = 0; i < buf->count; i++) { char *data = gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data); gpr_free(data); } } GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0); GPR_ASSERT(tcp->write_cb == NULL); if (buf->length == 0) { GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0); return GRPC_ENDPOINT_DONE; } tcp->outgoing_buffer = buf; tcp->outgoing_slice_idx = 0; tcp->outgoing_byte_idx = 0; status = tcp_flush(tcp); if (status == GRPC_ENDPOINT_PENDING) { TCP_REF(tcp, "write"); tcp->write_cb = cb; grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); } GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0); return status; } static void tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_add_fd(pollset, tcp->em_fd); } static void tcp_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_set_add_fd(pollset_set, tcp->em_fd); } static char *tcp_get_peer(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; return gpr_strdup(tcp->peer_string); } static const grpc_endpoint_vtable vtable = { tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, tcp_shutdown, tcp_destroy, tcp_get_peer}; grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, const char *peer_string) { grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); tcp->base.vtable = &vtable; tcp->peer_string = gpr_strdup(peer_string); tcp->fd = em_fd->fd; tcp->read_cb = NULL; tcp->write_cb = NULL; tcp->incoming_buffer = NULL; tcp->slice_size = slice_size; tcp->iov_size = 1; tcp->finished_edge = 1; /* paired with unref in grpc_tcp_destroy */ gpr_ref_init(&tcp->refcount, 1); tcp->em_fd = em_fd; tcp->read_closure.cb = tcp_handle_read; tcp->read_closure.cb_arg = tcp; tcp->write_closure.cb = tcp_handle_write; tcp->write_closure.cb_arg = tcp; return &tcp->base; } #endif grpc-0.11.1/src/core/iomgr/sockaddr_posix.h0000644000175000017500000000350412600663151020742 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H #include #include #include #include #include #include #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H */ grpc-0.11.1/src/core/iomgr/resolve_address_posix.c0000644000175000017500000001317312600663151022332 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/resolve_address.h" #include #include #include #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/support/string.h" #include #include #include #include #include #include typedef struct { char *name; char *default_port; grpc_resolve_cb cb; void *arg; grpc_iomgr_object iomgr_object; } request; grpc_resolved_addresses *grpc_blocking_resolve_address( const char *name, const char *default_port) { struct addrinfo hints; struct addrinfo *result = NULL, *resp; char *host; char *port; int s; size_t i; grpc_resolved_addresses *addrs = NULL; struct sockaddr_un *un; if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' && name[4] == ':' && name[5] != 0) { addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); addrs->naddrs = 1; addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address)); un = (struct sockaddr_un *)addrs->addrs->addr; un->sun_family = AF_UNIX; strcpy(un->sun_path, name + 5); addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; return addrs; } /* parse name, splitting it into host and port parts */ gpr_split_host_port(name, &host, &port); if (host == NULL) { gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); goto done; } if (port == NULL) { if (default_port == NULL) { gpr_log(GPR_ERROR, "no port in name '%s'", name); goto done; } port = gpr_strdup(default_port); } /* Call getaddrinfo */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ hints.ai_socktype = SOCK_STREAM; /* stream socket */ hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ s = getaddrinfo(host, port, &hints, &result); if (s != 0) { /* Retry if well-known service name is recognized */ char *svc[][2] = {{"http", "80"}, {"https", "443"}}; int i; for (i = 0; i < (int)(sizeof(svc) / sizeof(svc[0])); i++) { if (strcmp(port, svc[i][0]) == 0) { s = getaddrinfo(host, svc[i][1], &hints, &result); break; } } } if (s != 0) { gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); goto done; } /* Success path: set addrs non-NULL, fill it in */ addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); addrs->naddrs = 0; for (resp = result; resp != NULL; resp = resp->ai_next) { addrs->naddrs++; } addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); i = 0; for (resp = result; resp != NULL; resp = resp->ai_next) { memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); addrs->addrs[i].len = resp->ai_addrlen; i++; } done: gpr_free(host); gpr_free(port); if (result) { freeaddrinfo(result); } return addrs; } /* Thread function to asynch-ify grpc_blocking_resolve_address */ static void do_request(void *rp) { request *r = rp; grpc_resolved_addresses *resolved = grpc_blocking_resolve_address(r->name, r->default_port); void *arg = r->arg; grpc_resolve_cb cb = r->cb; gpr_free(r->name); gpr_free(r->default_port); cb(arg, resolved); grpc_iomgr_unregister_object(&r->iomgr_object); gpr_free(r); } void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { gpr_free(addrs->addrs); gpr_free(addrs); } void grpc_resolve_address(const char *name, const char *default_port, grpc_resolve_cb cb, void *arg) { request *r = gpr_malloc(sizeof(request)); gpr_thd_id id; char *tmp; gpr_asprintf(&tmp, "resolve_address:name='%s':default_port='%s'", name, default_port); grpc_iomgr_register_object(&r->iomgr_object, tmp); gpr_free(tmp); r->name = gpr_strdup(name); r->default_port = gpr_strdup(default_port); r->cb = cb; r->arg = arg; gpr_thd_new(&id, do_request, r, NULL); } #endif grpc-0.11.1/src/core/iomgr/socket_utils_posix.c0000644000175000017500000000460712600663151021660 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKETUTILS #include "src/core/iomgr/socket_utils_posix.h" #include #include #include #include int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int nonblock, int cloexec) { int fd, flags; fd = accept(sockfd, addr, addrlen); if (fd >= 0) { if (nonblock) { flags = fcntl(fd, F_GETFL, 0); if (flags < 0) goto close_and_error; if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error; } if (cloexec) { flags = fcntl(fd, F_GETFD, 0); if (flags < 0) goto close_and_error; if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error; } } return fd; close_and_error: close(fd); return -1; } #endif /* GPR_POSIX_SOCKETUTILS */ grpc-0.11.1/src/core/iomgr/tcp_client_windows.c0000644000175000017500000001552412600663151021624 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include "src/core/iomgr/sockaddr_win32.h" #include #include #include #include #include #include "src/core/iomgr/alarm.h" #include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_windows.h" #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_windows.h" typedef struct { void (*cb)(void *arg, grpc_endpoint *tcp); void *cb_arg; gpr_mu mu; grpc_winsocket *socket; gpr_timespec deadline; grpc_alarm alarm; char *addr_name; int refs; } async_connect; static void async_connect_unlock_and_cleanup(async_connect *ac) { int done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket); gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_name); gpr_free(ac); } } static void on_alarm(void *acp, int occured) { async_connect *ac = acp; gpr_mu_lock(&ac->mu); /* If the alarm didn't occur, it got cancelled. */ if (ac->socket != NULL && occured) { grpc_winsocket_shutdown(ac->socket); } async_connect_unlock_and_cleanup(ac); } static void on_connect(void *acp, int from_iocp) { async_connect *ac = acp; SOCKET sock = ac->socket->socket; grpc_endpoint *ep = NULL; grpc_winsocket_callback_info *info = &ac->socket->write_info; void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb; void *cb_arg = ac->cb_arg; grpc_alarm_cancel(&ac->alarm); gpr_mu_lock(&ac->mu); if (from_iocp) { DWORD transfered_bytes = 0; DWORD flags; BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, &transfered_bytes, FALSE, &flags); GPR_ASSERT(transfered_bytes == 0); if (!wsa_success) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); gpr_free(utf8_message); } else { ep = grpc_tcp_create(ac->socket, ac->addr_name); ac->socket = NULL; } } async_connect_unlock_and_cleanup(ac); /* If the connection was aborted, the callback was already called when the deadline was met. */ cb(cb_arg, ep); } /* Tries to issue one async connection, then schedules both an IOCP notification request for the connection, and one timeout alert. */ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp), void *arg, grpc_pollset_set *interested_parties, const struct sockaddr *addr, int addr_len, gpr_timespec deadline) { SOCKET sock = INVALID_SOCKET; BOOL success; int status; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in6 local_address; async_connect *ac; grpc_winsocket *socket = NULL; LPFN_CONNECTEX ConnectEx; GUID guid = WSAID_CONNECTEX; DWORD ioctl_num_bytes; const char *message = NULL; char *utf8_message; grpc_winsocket_callback_info *info; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { message = "Unable to create socket: %s"; goto failure; } if (!grpc_tcp_prepare_socket(sock)) { message = "Unable to set socket options: %s"; goto failure; } /* Grab the function pointer for ConnectEx for that specific socket. It may change depending on the interface. */ status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL); if (status != 0) { message = "Unable to retrieve ConnectEx pointer: %s"; goto failure; } grpc_sockaddr_make_wildcard6(0, &local_address); status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address)); if (status != 0) { message = "Unable to bind socket: %s"; goto failure; } socket = grpc_winsocket_create(sock, "client"); info = &socket->write_info; success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped); /* It wouldn't be unusual to get a success immediately. But we'll still get an IOCP notification, so let's ignore it. */ if (!success) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { message = "ConnectEx failed: %s"; goto failure; } } ac = gpr_malloc(sizeof(async_connect)); ac->cb = cb; ac->cb_arg = arg; ac->socket = socket; gpr_mu_init(&ac->mu); ac->refs = 2; ac->addr_name = grpc_sockaddr_to_uri(addr); grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_socket_notify_on_write(socket, on_connect, ac); return; failure: utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, message, utf8_message); gpr_free(utf8_message); if (socket != NULL) { grpc_winsocket_destroy(socket); } else if (sock != INVALID_SOCKET) { closesocket(sock); } cb(arg, NULL); } #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/wakeup_fd_eventfd.c0000644000175000017500000000532312600663151021402 0ustar apollockapollock/* * * 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 #ifdef GPR_LINUX_EVENTFD #include #include #include #include "src/core/iomgr/wakeup_fd_posix.h" #include static void eventfd_create(grpc_wakeup_fd *fd_info) { int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); /* TODO(klempner): Handle failure more gracefully */ GPR_ASSERT(efd >= 0); fd_info->read_fd = efd; fd_info->write_fd = -1; } static void eventfd_consume(grpc_wakeup_fd *fd_info) { eventfd_t value; int err; do { err = eventfd_read(fd_info->read_fd, &value); } while (err < 0 && errno == EINTR); } static void eventfd_wakeup(grpc_wakeup_fd *fd_info) { int err; do { err = eventfd_write(fd_info->read_fd, 1); } while (err < 0 && errno == EINTR); } static void eventfd_destroy(grpc_wakeup_fd *fd_info) { close(fd_info->read_fd); } static int eventfd_check_availability(void) { /* TODO(klempner): Actually check if eventfd is available */ return 1; } const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy, eventfd_check_availability}; #endif /* GPR_LINUX_EVENTFD */ grpc-0.11.1/src/core/iomgr/alarm.h0000644000175000017500000000764512600663151017034 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_ALARM_H #define GRPC_INTERNAL_CORE_IOMGR_ALARM_H #include "src/core/iomgr/iomgr.h" #include #include typedef struct grpc_alarm { gpr_timespec deadline; gpr_uint32 heap_index; /* INVALID_HEAP_INDEX if not in heap */ int triggered; struct grpc_alarm *next; struct grpc_alarm *prev; grpc_iomgr_cb_func cb; void *cb_arg; } grpc_alarm; /* Initialize *alarm. When expired or canceled, alarm_cb will be called with *alarm_cb_arg and status to indicate if it expired (SUCCESS) or was canceled (CANCELLED). alarm_cb is guaranteed to be called exactly once, and application code should check the status to determine how it was invoked. The application callback is also responsible for maintaining information about when to free up any user-level state. */ void grpc_alarm_init(grpc_alarm *alarm, gpr_timespec deadline, grpc_iomgr_cb_func alarm_cb, void *alarm_cb_arg, gpr_timespec now); /* Note that there is no alarm destroy function. This is because the alarm is a one-time occurrence with a guarantee that the callback will be called exactly once, either at expiration or cancellation. Thus, all the internal alarm event management state is destroyed just before that callback is invoked. If the user has additional state associated with the alarm, the user is responsible for determining when it is safe to destroy that state. */ /* Cancel an *alarm. There are three cases: 1. We normally cancel the alarm 2. The alarm has already run 3. We can't cancel the alarm because it is "in flight". In all of these cases, the cancellation is still considered successful. They are essentially distinguished in that the alarm_cb will be run exactly once from either the cancellation (with status CANCELLED) or from the activation (with status SUCCESS) Note carefully that the callback function MAY occur in the same callstack as grpc_alarm_cancel. It's expected that most alarms will be cancelled (their primary use is to implement deadlines), and so this code is optimized such that cancellation costs as little as possible. Making callbacks run inline matches this aim. Requires: cancel() must happen after add() on a given alarm */ void grpc_alarm_cancel(grpc_alarm *alarm); #endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_H */ grpc-0.11.1/src/core/iomgr/resolve_address_windows.c0000644000175000017500000001167712600663151022671 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/resolve_address.h" #include #include #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/support/string.h" #include #include #include #include #include #include typedef struct { char *name; char *default_port; grpc_resolve_cb cb; void *arg; grpc_iomgr_object iomgr_object; } request; grpc_resolved_addresses *grpc_blocking_resolve_address( const char *name, const char *default_port) { struct addrinfo hints; struct addrinfo *result = NULL, *resp; char *host; char *port; int s; size_t i; grpc_resolved_addresses *addrs = NULL; /* parse name, splitting it into host and port parts */ gpr_split_host_port(name, &host, &port); if (host == NULL) { gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); goto done; } if (port == NULL) { if (default_port == NULL) { gpr_log(GPR_ERROR, "no port in name '%s'", name); goto done; } port = gpr_strdup(default_port); } /* Call getaddrinfo */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ hints.ai_socktype = SOCK_STREAM; /* stream socket */ hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ s = getaddrinfo(host, port, &hints, &result); if (s != 0) { gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); goto done; } /* Success path: set addrs non-NULL, fill it in */ addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); addrs->naddrs = 0; for (resp = result; resp != NULL; resp = resp->ai_next) { addrs->naddrs++; } addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); i = 0; for (resp = result; resp != NULL; resp = resp->ai_next) { memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); addrs->addrs[i].len = resp->ai_addrlen; i++; } { for (i = 0; i < addrs->naddrs; i++) { char *buf; grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, 0); gpr_free(buf); } } done: gpr_free(host); gpr_free(port); if (result) { freeaddrinfo(result); } return addrs; } /* Thread function to asynch-ify grpc_blocking_resolve_address */ static void do_request(void *rp) { request *r = rp; grpc_resolved_addresses *resolved = grpc_blocking_resolve_address(r->name, r->default_port); void *arg = r->arg; grpc_resolve_cb cb = r->cb; gpr_free(r->name); gpr_free(r->default_port); grpc_iomgr_unregister_object(&r->iomgr_object); gpr_free(r); cb(arg, resolved); } void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { gpr_free(addrs->addrs); gpr_free(addrs); } void grpc_resolve_address(const char *name, const char *default_port, grpc_resolve_cb cb, void *arg) { request *r = gpr_malloc(sizeof(request)); gpr_thd_id id; const char *label; gpr_asprintf(&label, "resolve:%s", name); grpc_iomgr_register_object(&r->iomgr_object, label); gpr_free(label); r->name = gpr_strdup(name); r->default_port = gpr_strdup(default_port); r->cb = cb; r->arg = arg; gpr_thd_new(&id, do_request, r, NULL); } #endif grpc-0.11.1/src/core/iomgr/iocp_windows.c0000644000175000017500000001454512600663151020434 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include #include #include #include #include #include "src/core/iomgr/alarm_internal.h" #include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/socket_windows.h" static ULONG g_iocp_kick_token; static OVERLAPPED g_iocp_custom_overlap; static gpr_event g_shutdown_iocp; static gpr_event g_iocp_done; static gpr_atm g_custom_events = 0; static HANDLE g_iocp; static void do_iocp_work() { BOOL success; DWORD bytes = 0; DWORD flags = 0; ULONG_PTR completion_key; LPOVERLAPPED overlapped; grpc_winsocket *socket; grpc_winsocket_callback_info *info; void (*f)(void *, int) = NULL; void *opaque = NULL; success = GetQueuedCompletionStatus(g_iocp, &bytes, &completion_key, &overlapped, INFINITE); /* success = 0 and overlapped = NULL means the deadline got attained. Which is impossible. since our wait time is +inf */ GPR_ASSERT(success || overlapped); GPR_ASSERT(completion_key && overlapped); if (overlapped == &g_iocp_custom_overlap) { gpr_atm_full_fetch_add(&g_custom_events, -1); if (completion_key == (ULONG_PTR)&g_iocp_kick_token) { /* We were awoken from a kick. */ return; } gpr_log(GPR_ERROR, "Unknown custom completion key."); abort(); } socket = (grpc_winsocket *)completion_key; if (overlapped == &socket->write_info.overlapped) { info = &socket->write_info; } else if (overlapped == &socket->read_info.overlapped) { info = &socket->read_info; } else { gpr_log(GPR_ERROR, "Unknown IOCP operation"); abort(); } success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, FALSE, &flags); info->bytes_transfered = bytes; info->wsa_error = success ? 0 : WSAGetLastError(); GPR_ASSERT(overlapped == &info->overlapped); GPR_ASSERT(!info->has_pending_iocp); gpr_mu_lock(&socket->state_mu); if (info->cb) { f = info->cb; opaque = info->opaque; info->cb = NULL; } else { info->has_pending_iocp = 1; } gpr_mu_unlock(&socket->state_mu); if (f) f(opaque, 1); } static void iocp_loop(void *p) { while (gpr_atm_acq_load(&g_custom_events) || !gpr_event_get(&g_shutdown_iocp)) { do_iocp_work(); } gpr_event_set(&g_iocp_done, (void *)1); } void grpc_iocp_init(void) { gpr_thd_id id; g_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); GPR_ASSERT(g_iocp); gpr_event_init(&g_iocp_done); gpr_event_init(&g_shutdown_iocp); gpr_thd_new(&id, iocp_loop, NULL, NULL); } void grpc_iocp_kick(void) { BOOL success; gpr_atm_full_fetch_add(&g_custom_events, 1); success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token, &g_iocp_custom_overlap); GPR_ASSERT(success); } void grpc_iocp_shutdown(void) { BOOL success; gpr_event_set(&g_shutdown_iocp, (void *)1); grpc_iocp_kick(); gpr_event_wait(&g_iocp_done, gpr_inf_future(GPR_CLOCK_REALTIME)); success = CloseHandle(g_iocp); GPR_ASSERT(success); } void grpc_iocp_add_socket(grpc_winsocket *socket) { HANDLE ret; if (socket->added_to_iocp) return; ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp, (gpr_uintptr)socket, 0); if (!ret) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); gpr_free(utf8_message); __debugbreak(); abort(); } socket->added_to_iocp = 1; GPR_ASSERT(ret == g_iocp); } /* Calling notify_on_read or write means either of two things: -) The IOCP already completed in the background, and we need to call the callback now. -) The IOCP hasn't completed yet, and we're queuing it for later. */ static void socket_notify_on_iocp(grpc_winsocket *socket, void (*cb)(void *, int), void *opaque, grpc_winsocket_callback_info *info) { int run_now = 0; GPR_ASSERT(!info->cb); gpr_mu_lock(&socket->state_mu); if (info->has_pending_iocp) { run_now = 1; info->has_pending_iocp = 0; } else { info->cb = cb; info->opaque = opaque; } gpr_mu_unlock(&socket->state_mu); if (run_now) cb(opaque, 1); } void grpc_socket_notify_on_write(grpc_winsocket *socket, void (*cb)(void *, int), void *opaque) { socket_notify_on_iocp(socket, cb, opaque, &socket->write_info); } void grpc_socket_notify_on_read(grpc_winsocket *socket, void (*cb)(void *, int), void *opaque) { socket_notify_on_iocp(socket, cb, opaque, &socket->read_info); } #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/sockaddr_utils.c0000644000175000017500000001671212600663151020740 0ustar apollockapollock/* * * 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/iomgr/sockaddr_utils.h" #include #include #ifdef GPR_POSIX_SOCKET #include #endif #include #include #include #include #include #include "src/core/support/string.h" static const gpr_uint8 kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, struct sockaddr_in *addr4_out) { GPR_ASSERT(addr != (struct sockaddr *)addr4_out); if (addr->sa_family == AF_INET6) { const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix, sizeof(kV4MappedPrefix)) == 0) { if (addr4_out != NULL) { /* Normalize ::ffff:0.0.0.0/96 to IPv4. */ memset(addr4_out, 0, sizeof(*addr4_out)); addr4_out->sin_family = AF_INET; /* s6_addr32 would be nice, but it's non-standard. */ memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4); addr4_out->sin_port = addr6->sin6_port; } return 1; } } return 0; } int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, struct sockaddr_in6 *addr6_out) { GPR_ASSERT(addr != (struct sockaddr *)addr6_out); if (addr->sa_family == AF_INET) { const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; memset(addr6_out, 0, sizeof(*addr6_out)); addr6_out->sin6_family = AF_INET6; memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12); memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4); addr6_out->sin6_port = addr4->sin_port; return 1; } return 0; } int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) { struct sockaddr_in addr4_normalized; if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) { addr = (struct sockaddr *)&addr4_normalized; } if (addr->sa_family == AF_INET) { /* Check for 0.0.0.0 */ const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; if (addr4->sin_addr.s_addr != 0) { return 0; } *port_out = ntohs(addr4->sin_port); return 1; } else if (addr->sa_family == AF_INET6) { /* Check for :: */ const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; int i; for (i = 0; i < 16; i++) { if (addr6->sin6_addr.s6_addr[i] != 0) { return 0; } } *port_out = ntohs(addr6->sin6_port); return 1; } else { return 0; } } void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, struct sockaddr_in6 *wild6_out) { grpc_sockaddr_make_wildcard4(port, wild4_out); grpc_sockaddr_make_wildcard6(port, wild6_out); } void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) { memset(wild_out, 0, sizeof(*wild_out)); wild_out->sin_family = AF_INET; wild_out->sin_port = htons(port); } void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) { memset(wild_out, 0, sizeof(*wild_out)); wild_out->sin6_family = AF_INET6; wild_out->sin6_port = htons(port); } int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, int normalize) { const int save_errno = errno; struct sockaddr_in addr_normalized; char ntop_buf[INET6_ADDRSTRLEN]; const void *ip = NULL; int port; int ret; *out = NULL; if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { addr = (const struct sockaddr *)&addr_normalized; } if (addr->sa_family == AF_INET) { const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; ip = &addr4->sin_addr; port = ntohs(addr4->sin_port); } else if (addr->sa_family == AF_INET6) { const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; ip = &addr6->sin6_addr; port = ntohs(addr6->sin6_port); } if (ip != NULL && inet_ntop(addr->sa_family, ip, ntop_buf, sizeof(ntop_buf)) != NULL) { ret = gpr_join_host_port(out, ntop_buf, port); } else { ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family); } /* This is probably redundant, but we wouldn't want to log the wrong error. */ errno = save_errno; return ret; } char *grpc_sockaddr_to_uri(const struct sockaddr *addr) { char *temp; char *result; struct sockaddr_in addr_normalized; if (grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { addr = (const struct sockaddr *)&addr_normalized; } switch (addr->sa_family) { case AF_INET: grpc_sockaddr_to_string(&temp, addr, 0); gpr_asprintf(&result, "ipv4:%s", temp); gpr_free(temp); return result; case AF_INET6: grpc_sockaddr_to_string(&temp, addr, 0); gpr_asprintf(&result, "ipv6:%s", temp); gpr_free(temp); return result; #ifdef GPR_POSIX_SOCKET case AF_UNIX: gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path); return result; #endif } return NULL; } int grpc_sockaddr_get_port(const struct sockaddr *addr) { switch (addr->sa_family) { case AF_INET: return ntohs(((struct sockaddr_in *)addr)->sin_port); case AF_INET6: return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); case AF_UNIX: return 1; default: gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", addr->sa_family); return 0; } } int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) { switch (addr->sa_family) { case AF_INET: ((struct sockaddr_in *)addr)->sin_port = htons(port); return 1; case AF_INET6: ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); return 1; default: gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", addr->sa_family); return 0; } } grpc-0.11.1/src/core/iomgr/wakeup_fd_pipe.h0000644000175000017500000000344512600663151020714 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H #define GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H #include "src/core/iomgr/wakeup_fd_posix.h" extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable; #endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H */ grpc-0.11.1/src/core/iomgr/socket_windows.c0000644000175000017500000000723512600663151020770 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include #include #include #include #include #include #include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_windows.h" #include "src/core/iomgr/socket_windows.h" grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) { char *final_name; grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket)); memset(r, 0, sizeof(grpc_winsocket)); r->socket = socket; gpr_mu_init(&r->state_mu); gpr_asprintf(&final_name, "%s:socket=0x%p", name, r); grpc_iomgr_register_object(&r->iomgr_object, final_name); gpr_free(final_name); grpc_iocp_add_socket(r); return r; } /* Schedule a shutdown of the socket operations. Will call the pending operations to abort them. We need to do that this way because of the various callsites of that function, which happens to be in various mutex hold states, and that'd be unsafe to call them directly. */ void grpc_winsocket_shutdown(grpc_winsocket *winsocket) { /* Grab the function pointer for DisconnectEx for that specific socket. It may change depending on the interface. */ int status; GUID guid = WSAID_DISCONNECTEX; LPFN_DISCONNECTEX DisconnectEx; DWORD ioctl_num_bytes; status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx), &ioctl_num_bytes, NULL, NULL); if (status == 0) { DisconnectEx(winsocket->socket, NULL, 0, 0); } else { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s", utf8_message); gpr_free(utf8_message); } closesocket(winsocket->socket); } void grpc_winsocket_destroy(grpc_winsocket *winsocket) { grpc_iomgr_unregister_object(&winsocket->iomgr_object); gpr_mu_destroy(&winsocket->state_mu); gpr_free(winsocket); } #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/pollset_windows.c0000644000175000017500000001206112600663151021153 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include #include "src/core/iomgr/alarm_internal.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_windows.h" static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->prev->next = worker->next; worker->next->prev = worker->prev; } static int has_workers(grpc_pollset *p) { return p->root_worker.next != &p->root_worker; } static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { if (has_workers(p)) { grpc_pollset_worker *w = p->root_worker.next; remove_worker(p, w); return w; } else { return NULL; } } static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->next = &p->root_worker; worker->prev = worker->next->prev; worker->prev->next = worker->next->prev = worker; } static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->prev = &p->root_worker; worker->next = worker->prev->next; worker->prev->next = worker->next->prev = worker; } /* There isn't really any such thing as a pollset under Windows, due to the nature of the IO completion ports. We're still going to provide a minimal set of features for the sake of the rest of grpc. But grpc_pollset_work won't actually do any polling, and return as quickly as possible. */ void grpc_pollset_init(grpc_pollset *pollset) { memset(pollset, 0, sizeof(*pollset)); gpr_mu_init(&pollset->mu); pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; pollset->kicked_without_pollers = 0; } void grpc_pollset_shutdown(grpc_pollset *pollset, void (*shutdown_done)(void *arg), void *shutdown_done_arg) { gpr_mu_lock(&pollset->mu); pollset->shutting_down = 1; grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); gpr_mu_unlock(&pollset->mu); shutdown_done(shutdown_done_arg); } void grpc_pollset_destroy(grpc_pollset *pollset) { gpr_mu_destroy(&pollset->mu); } void grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec now, gpr_timespec deadline) { int added_worker = 0; worker->next = worker->prev = NULL; gpr_cv_init(&worker->cv); if (grpc_maybe_call_delayed_callbacks(&pollset->mu, 1 /* GPR_TRUE */)) { goto done; } if (grpc_alarm_check(&pollset->mu, now, &deadline)) { goto done; } if (!pollset->kicked_without_pollers && !pollset->shutting_down) { push_front_worker(pollset, worker); added_worker = 1; gpr_cv_wait(&worker->cv, &pollset->mu, deadline); } else { pollset->kicked_without_pollers = 0; } done: gpr_cv_destroy(&worker->cv); if (added_worker) { remove_worker(pollset, worker); } } void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { if (specific_worker != NULL) { if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { for (specific_worker = p->root_worker.next; specific_worker != &p->root_worker; specific_worker = specific_worker->next) { gpr_cv_signal(&specific_worker->cv); } p->kicked_without_pollers = 1; } else { gpr_cv_signal(&specific_worker->cv); } } else { specific_worker = pop_front_worker(p); if (specific_worker != NULL) { push_back_worker(p, specific_worker); gpr_cv_signal(&specific_worker->cv); } else { p->kicked_without_pollers = 1; } } } #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/udp_server.h0000644000175000017500000000723612600663151020112 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H #define GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H #include "src/core/iomgr/endpoint.h" /* Forward decl of grpc_udp_server */ typedef struct grpc_udp_server grpc_udp_server; /* New server callback: ep is the newly connected connection */ typedef void (*grpc_udp_server_cb)(void *arg, grpc_endpoint *ep); /* Called when data is available to read from the socket. */ typedef void (*grpc_udp_server_read_cb)(int fd, grpc_udp_server_cb new_transport_cb, void *cb_arg); /* Create a server, initially not bound to any ports */ grpc_udp_server *grpc_udp_server_create(void); /* Start listening to bound ports */ void grpc_udp_server_start(grpc_udp_server *server, grpc_pollset **pollsets, size_t pollset_count, grpc_udp_server_cb cb, void *cb_arg); int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index); /* Add a port to the server, returning port number on success, or negative on failure. The :: and 0.0.0.0 wildcard addresses are treated identically, accepting both IPv4 and IPv6 connections, but :: is the preferred style. This usually creates one socket, but possibly two on systems which support IPv6, but not dualstack sockets. */ /* 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, int addr_len, grpc_udp_server_read_cb read_cb); void grpc_udp_server_destroy(grpc_udp_server *server, void (*shutdown_done)(void *shutdown_done_arg), void *shutdown_done_arg); /* Write the contents of buffer to the underlying UDP socket. */ /* void grpc_udp_server_write(grpc_udp_server *s, const char *buffer, int buf_len, const struct sockaddr* to); */ #endif /* GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H */ grpc-0.11.1/src/core/iomgr/sockaddr.h0000644000175000017500000000355012600663151017521 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H #define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H #include #ifdef GPR_WIN32 #include "src/core/iomgr/sockaddr_win32.h" #endif #ifdef GPR_POSIX_SOCKETADDR #include "src/core/iomgr/sockaddr_posix.h" #endif #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H */ grpc-0.11.1/src/core/iomgr/iomgr_posix.c0000644000175000017500000000402512600663151020257 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/iomgr_posix.h" #include "src/core/debug/trace.h" #include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/tcp_posix.h" void grpc_iomgr_platform_init(void) { grpc_fd_global_init(); grpc_pollset_global_init(); grpc_register_tracer("tcp", &grpc_tcp_trace); } void grpc_iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); grpc_fd_global_shutdown(); } #endif /* GRPC_POSIX_SOCKET */ grpc-0.11.1/src/core/iomgr/fd_posix.h0000644000175000017500000001655012600663151017546 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/pollset.h" #include #include #include typedef struct grpc_fd grpc_fd; typedef struct grpc_fd_watcher { struct grpc_fd_watcher *next; struct grpc_fd_watcher *prev; grpc_pollset *pollset; grpc_fd *fd; } grpc_fd_watcher; struct grpc_fd { int fd; /* refst format: bit0: 1=active/0=orphaned bit1-n: refcount meaning that mostly we ref by two to avoid altering the orphaned bit, and just unref by 1 when we're ready to flag the object as orphaned */ gpr_atm refst; gpr_mu set_state_mu; gpr_atm shutdown; int closed; /* The watcher list. The following watcher related fields are protected by watcher_mu. An fd_watcher is an ephemeral object created when an fd wants to begin polling, and destroyed after the poll. It denotes the fd's interest in whether to read poll or write poll or both or neither on this fd. If a watcher is asked to poll for reads or writes, the read_watcher or write_watcher fields are set respectively. A watcher may be asked to poll for both, in which case both fields will be set. read_watcher and write_watcher may be NULL if no watcher has been asked to poll for reads or writes. If an fd_watcher is not asked to poll for reads or writes, it's added to a linked list of inactive watchers, rooted at inactive_watcher_root. If at a later time there becomes need of a poller to poll, one of the inactive pollers may be kicked out of their poll loops to take that responsibility. */ gpr_mu watcher_mu; grpc_fd_watcher inactive_watcher_root; grpc_fd_watcher *read_watcher; grpc_fd_watcher *write_watcher; gpr_atm readst; gpr_atm writest; struct grpc_fd *freelist_next; grpc_iomgr_closure *on_done_closure; grpc_iomgr_closure *shutdown_closures[2]; grpc_iomgr_object iomgr_object; }; /* Create a wrapped file descriptor. Requires fd is a non-blocking file descriptor. This takes ownership of closing fd. */ grpc_fd *grpc_fd_create(int fd, const char *name); /* Releases fd to be asynchronously destroyed. on_done is called when the underlying file descriptor is definitely close()d. If on_done is NULL, no callback will be made. Requires: *fd initialized; no outstanding notify_on_read or notify_on_write. MUST NOT be called with a pollset lock taken */ void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done, const char *reason); /* Begin polling on an fd. Registers that the given pollset is interested in this fd - so that if read or writability interest changes, the pollset can be kicked to pick up that new interest. Return value is: (fd_needs_read? read_mask : 0) | (fd_needs_write? write_mask : 0) i.e. a combination of read_mask and write_mask determined by the fd's current interest in said events. Polling strategies that do not need to alter their behavior depending on the fd's current interest (such as epoll) do not need to call this function. MUST NOT be called with a pollset lock taken */ gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, gpr_uint32 read_mask, gpr_uint32 write_mask, grpc_fd_watcher *rec); /* Complete polling previously started with grpc_fd_begin_poll MUST NOT be called with a pollset lock taken */ void grpc_fd_end_poll(grpc_fd_watcher *rec, int got_read, int got_write); /* Return 1 if this fd is orphaned, 0 otherwise */ int grpc_fd_is_orphaned(grpc_fd *fd); /* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */ void grpc_fd_shutdown(grpc_fd *fd); /* Register read interest, causing read_cb to be called once when fd becomes readable, on deadline specified by deadline, or on shutdown triggered by grpc_fd_shutdown. read_cb will be called with read_cb_arg when *fd becomes readable. read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable, GRPC_CALLBACK_TIMED_OUT if the call timed out, and CANCELLED if the call was cancelled. Requires:This method must not be called before the read_cb for any previous call runs. Edge triggered events are used whenever they are supported by the underlying platform. This means that users must drain fd in read_cb before calling notify_on_read again. Users are also expected to handle spurious events, i.e read_cb is called while nothing can be readable from fd */ void grpc_fd_notify_on_read(grpc_fd *fd, grpc_iomgr_closure *closure); /* Exactly the same semantics as above, except based on writable events. */ void grpc_fd_notify_on_write(grpc_fd *fd, grpc_iomgr_closure *closure); /* Notification from the poller to an fd that it has become readable or writable. If allow_synchronous_callback is 1, allow running the fd callback inline in this callstack, otherwise register an asynchronous callback and return */ void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback); void grpc_fd_become_writable(grpc_fd *fd, int allow_synchronous_callback); /* Reference counting for fds */ #ifdef GRPC_FD_REF_COUNT_DEBUG void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line); #define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd, reason, __FILE__, __LINE__) #define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd, reason, __FILE__, __LINE__) #else void grpc_fd_ref(grpc_fd *fd); void grpc_fd_unref(grpc_fd *fd); #define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd) #define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd) #endif void grpc_fd_global_init(void); void grpc_fd_global_shutdown(void); #endif /* GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H */ grpc-0.11.1/src/core/iomgr/endpoint_pair_windows.c0000644000175000017500000000707612600663151022336 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/endpoint_pair.h" #include #include #include #include "src/core/iomgr/tcp_windows.h" #include "src/core/iomgr/socket_windows.h" #include static void create_sockets(SOCKET sv[2]) { SOCKET svr_sock = INVALID_SOCKET; SOCKET lst_sock = INVALID_SOCKET; SOCKET cli_sock = INVALID_SOCKET; SOCKADDR_IN addr; int addr_len = sizeof(addr); lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); GPR_ASSERT(lst_sock != INVALID_SOCKET); memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_family = AF_INET; GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) != SOCKET_ERROR); GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR); GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) != SOCKET_ERROR); cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); GPR_ASSERT(cli_sock != INVALID_SOCKET); GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL, NULL, NULL, NULL) == 0); svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len); GPR_ASSERT(svr_sock != INVALID_SOCKET); closesocket(lst_sock); grpc_tcp_prepare_socket(cli_sock); grpc_tcp_prepare_socket(svr_sock); sv[1] = cli_sock; sv[0] = svr_sock; } grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size) { SOCKET sv[2]; grpc_endpoint_pair p; create_sockets(sv); p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"), "endpoint:server"); p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"), "endpoint:client"); return p; } #endif grpc-0.11.1/src/core/iomgr/alarm_heap.h0000644000175000017500000000441412600663151020020 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H #define GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H #include "src/core/iomgr/alarm.h" typedef struct { grpc_alarm **alarms; int alarm_count; int alarm_capacity; } grpc_alarm_heap; /* return 1 if the new alarm is the first alarm in the heap */ int grpc_alarm_heap_add(grpc_alarm_heap *heap, grpc_alarm *alarm); void grpc_alarm_heap_init(grpc_alarm_heap *heap); void grpc_alarm_heap_destroy(grpc_alarm_heap *heap); void grpc_alarm_heap_remove(grpc_alarm_heap *heap, grpc_alarm *alarm); grpc_alarm *grpc_alarm_heap_top(grpc_alarm_heap *heap); void grpc_alarm_heap_pop(grpc_alarm_heap *heap); int grpc_alarm_heap_is_empty(grpc_alarm_heap *heap); #endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H */ grpc-0.11.1/src/core/iomgr/iomgr.h0000644000175000017500000000603512600663151017045 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_H #define GRPC_INTERNAL_CORE_IOMGR_IOMGR_H /** gRPC Callback definition. * * \param arg Arbitrary input. * \param success An indication on the state of the iomgr. On false, cleanup * actions should be taken (eg, shutdown). */ typedef void (*grpc_iomgr_cb_func)(void *arg, int success); /** A closure over a grpc_iomgr_cb_func. */ typedef struct grpc_iomgr_closure { /** Bound callback. */ grpc_iomgr_cb_func cb; /** Arguments to be passed to "cb". */ void *cb_arg; /** Internal. A boolean indication to "cb" on the state of the iomgr. * For instance, closures created during a shutdown would have this field set * to false. */ int success; /**< Internal. Do not touch */ struct grpc_iomgr_closure *next; } grpc_iomgr_closure; /** Initializes \a closure with \a cb and \a cb_arg. */ void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb, void *cb_arg); /** Initializes the iomgr. */ void grpc_iomgr_init(void); /** Signals the intention to shutdown the iomgr. */ void grpc_iomgr_shutdown(void); /** Registers a closure to be invoked at some point in the future. * * Can be called from within a callback or from anywhere else */ void grpc_iomgr_add_callback(grpc_iomgr_closure *closure); /** As per grpc_iomgr_add_callback, with the ability to set the success argument. */ void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *iocb, int success); #endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */ grpc-0.11.1/src/core/iomgr/wakeup_fd_posix.h0000644000175000017500000001010212600663151021105 0ustar apollockapollock/* * * 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. * */ /* * wakeup_fd abstracts the concept of a file descriptor for the purpose of * waking up a thread in select()/poll()/epoll_wait()/etc. * The poll() family of system calls provide a way for a thread to block until * there is activity on one (or more) of a set of file descriptors. An * application may wish to wake up this thread to do non file related work. The * typical way to do this is to add a pipe to the set of file descriptors, then * write to the pipe to wake up the thread in poll(). * * Linux has a lighter weight eventfd specifically designed for this purpose. * wakeup_fd abstracts the difference between the two. * * Setup: * 1. Before calling anything, call global_init() at least once. * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd. * 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file * descriptors for the poll() style API you are using. Monitor the file * descriptor for readability. * 3. To tear down, call grpc_wakeup_fd_destroy(). This closes the underlying * file descriptor. * * Usage: * 1. To wake up a polling thread, call grpc_wakeup_fd_wakeup() on a wakeup_fd * it is monitoring. * 2. If the polling thread was awakened by a wakeup_fd event, call * grpc_wakeup_fd_consume_wakeup() on it. */ #ifndef GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H void grpc_wakeup_fd_global_init(void); void grpc_wakeup_fd_global_destroy(void); /* Force using the fallback implementation. This is intended for testing * purposes only.*/ void grpc_wakeup_fd_global_init_force_fallback(void); typedef struct grpc_wakeup_fd grpc_wakeup_fd; typedef struct grpc_wakeup_fd_vtable { void (*init)(grpc_wakeup_fd *fd_info); void (*consume)(grpc_wakeup_fd *fd_info); void (*wakeup)(grpc_wakeup_fd *fd_info); void (*destroy)(grpc_wakeup_fd *fd_info); /* Must be called before calling any other functions */ int (*check_availability)(void); } grpc_wakeup_fd_vtable; struct grpc_wakeup_fd { int read_fd; int write_fd; }; #define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd) void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info); void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info); void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info); void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info); /* Defined in some specialized implementation's .c file, or by * wakeup_fd_nospecial.c if no such implementation exists. */ extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable; #endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H */ grpc-0.11.1/src/core/iomgr/endpoint.c0000644000175000017500000000513312600663151017541 0ustar apollockapollock/* * * 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/iomgr/endpoint.h" grpc_endpoint_op_status grpc_endpoint_read(grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) { return ep->vtable->read(ep, slices, cb); } grpc_endpoint_op_status grpc_endpoint_write(grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) { return ep->vtable->write(ep, slices, cb); } void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { ep->vtable->add_to_pollset(ep, pollset); } void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) { ep->vtable->add_to_pollset_set(ep, pollset_set); } void grpc_endpoint_shutdown(grpc_endpoint *ep) { ep->vtable->shutdown(ep); } void grpc_endpoint_destroy(grpc_endpoint *ep) { ep->vtable->destroy(ep); } char *grpc_endpoint_get_peer(grpc_endpoint *ep) { return ep->vtable->get_peer(ep); } grpc-0.11.1/src/core/iomgr/alarm.c0000644000175000017500000003127512600663151017023 0ustar apollockapollock/* * * 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/iomgr/alarm.h" #include "src/core/iomgr/alarm_heap.h" #include "src/core/iomgr/alarm_internal.h" #include "src/core/iomgr/time_averaged_stats.h" #include #include #include #define INVALID_HEAP_INDEX 0xffffffffu #define LOG2_NUM_SHARDS 5 #define NUM_SHARDS (1 << LOG2_NUM_SHARDS) #define MAX_ALARMS_PER_CHECK 128 #define ADD_DEADLINE_SCALE 0.33 #define MIN_QUEUE_WINDOW_DURATION 0.01 #define MAX_QUEUE_WINDOW_DURATION 1 typedef struct { gpr_mu mu; grpc_time_averaged_stats stats; /* All and only alarms with deadlines <= this will be in the heap. */ gpr_timespec queue_deadline_cap; gpr_timespec min_deadline; /* Index in the g_shard_queue */ gpr_uint32 shard_queue_index; /* This holds all alarms with deadlines < queue_deadline_cap. Alarms in this list have the top bit of their deadline set to 0. */ grpc_alarm_heap heap; /* This holds alarms whose deadline is >= queue_deadline_cap. */ grpc_alarm list; } shard_type; /* Protects g_shard_queue */ static gpr_mu g_mu; /* Allow only one run_some_expired_alarms at once */ static gpr_mu g_checker_mu; static gpr_clock_type g_clock_type; static shard_type g_shards[NUM_SHARDS]; /* Protected by g_mu */ static shard_type *g_shard_queue[NUM_SHARDS]; static int run_some_expired_alarms(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next, int success); static gpr_timespec compute_min_deadline(shard_type *shard) { return grpc_alarm_heap_is_empty(&shard->heap) ? shard->queue_deadline_cap : grpc_alarm_heap_top(&shard->heap)->deadline; } void grpc_alarm_list_init(gpr_timespec now) { int i; gpr_mu_init(&g_mu); gpr_mu_init(&g_checker_mu); g_clock_type = now.clock_type; for (i = 0; i < NUM_SHARDS; i++) { shard_type *shard = &g_shards[i]; gpr_mu_init(&shard->mu); grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1, 0.5); shard->queue_deadline_cap = now; shard->shard_queue_index = i; grpc_alarm_heap_init(&shard->heap); shard->list.next = shard->list.prev = &shard->list; shard->min_deadline = compute_min_deadline(shard); g_shard_queue[i] = shard; } } void grpc_alarm_list_shutdown(void) { int i; while (run_some_expired_alarms(NULL, gpr_inf_future(g_clock_type), NULL, 0)) ; for (i = 0; i < NUM_SHARDS; i++) { shard_type *shard = &g_shards[i]; gpr_mu_destroy(&shard->mu); grpc_alarm_heap_destroy(&shard->heap); } gpr_mu_destroy(&g_mu); gpr_mu_destroy(&g_checker_mu); } /* This is a cheap, but good enough, pointer hash for sharding the tasks: */ static size_t shard_idx(const grpc_alarm *info) { size_t x = (size_t)info; return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) & (NUM_SHARDS - 1); } static double ts_to_dbl(gpr_timespec ts) { return ts.tv_sec + 1e-9 * ts.tv_nsec; } static gpr_timespec dbl_to_ts(double d) { gpr_timespec ts; ts.tv_sec = d; ts.tv_nsec = 1e9 * (d - ts.tv_sec); ts.clock_type = GPR_TIMESPAN; return ts; } static void list_join(grpc_alarm *head, grpc_alarm *alarm) { alarm->next = head; alarm->prev = head->prev; alarm->next->prev = alarm->prev->next = alarm; } static void list_remove(grpc_alarm *alarm) { alarm->next->prev = alarm->prev; alarm->prev->next = alarm->next; } static void swap_adjacent_shards_in_queue(size_t first_shard_queue_index) { shard_type *temp; temp = g_shard_queue[first_shard_queue_index]; g_shard_queue[first_shard_queue_index] = g_shard_queue[first_shard_queue_index + 1]; g_shard_queue[first_shard_queue_index + 1] = temp; g_shard_queue[first_shard_queue_index]->shard_queue_index = first_shard_queue_index; g_shard_queue[first_shard_queue_index + 1]->shard_queue_index = first_shard_queue_index + 1; } static void note_deadline_change(shard_type *shard) { while (shard->shard_queue_index > 0 && gpr_time_cmp( shard->min_deadline, g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) { swap_adjacent_shards_in_queue(shard->shard_queue_index - 1); } while (shard->shard_queue_index < NUM_SHARDS - 1 && gpr_time_cmp( shard->min_deadline, g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) { swap_adjacent_shards_in_queue(shard->shard_queue_index); } } void grpc_alarm_init(grpc_alarm *alarm, gpr_timespec deadline, grpc_iomgr_cb_func alarm_cb, void *alarm_cb_arg, gpr_timespec now) { int is_first_alarm = 0; shard_type *shard = &g_shards[shard_idx(alarm)]; GPR_ASSERT(deadline.clock_type == g_clock_type); GPR_ASSERT(now.clock_type == g_clock_type); alarm->cb = alarm_cb; alarm->cb_arg = alarm_cb_arg; alarm->deadline = deadline; alarm->triggered = 0; /* TODO(ctiller): check deadline expired */ gpr_mu_lock(&shard->mu); grpc_time_averaged_stats_add_sample(&shard->stats, ts_to_dbl(gpr_time_sub(deadline, now))); if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) { is_first_alarm = grpc_alarm_heap_add(&shard->heap, alarm); } else { alarm->heap_index = INVALID_HEAP_INDEX; list_join(&shard->list, alarm); } gpr_mu_unlock(&shard->mu); /* Deadline may have decreased, we need to adjust the master queue. Note that there is a potential racy unlocked region here. There could be a reordering of multiple grpc_alarm_init calls, at this point, but the < test below should ensure that we err on the side of caution. There could also be a race with grpc_alarm_check, which might beat us to the lock. In that case, it is possible that the alarm that we added will have already run by the time we hold the lock, but that too is a safe error. Finally, it's possible that the grpc_alarm_check that intervened failed to trigger the new alarm because the min_deadline hadn't yet been reduced. In that case, the alarm will simply have to wait for the next grpc_alarm_check. */ if (is_first_alarm) { gpr_mu_lock(&g_mu); if (gpr_time_cmp(deadline, shard->min_deadline) < 0) { gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline; shard->min_deadline = deadline; note_deadline_change(shard); if (shard->shard_queue_index == 0 && gpr_time_cmp(deadline, old_min_deadline) < 0) { grpc_kick_poller(); } } gpr_mu_unlock(&g_mu); } } void grpc_alarm_cancel(grpc_alarm *alarm) { shard_type *shard = &g_shards[shard_idx(alarm)]; int triggered = 0; gpr_mu_lock(&shard->mu); if (!alarm->triggered) { triggered = 1; alarm->triggered = 1; if (alarm->heap_index == INVALID_HEAP_INDEX) { list_remove(alarm); } else { grpc_alarm_heap_remove(&shard->heap, alarm); } } gpr_mu_unlock(&shard->mu); if (triggered) { alarm->cb(alarm->cb_arg, 0); } } /* This is called when the queue is empty and "now" has reached the queue_deadline_cap. We compute a new queue deadline and then scan the map for alarms that fall at or under it. Returns true if the queue is no longer empty. REQUIRES: shard->mu locked */ static int refill_queue(shard_type *shard, gpr_timespec now) { /* Compute the new queue window width and bound by the limits: */ double computed_deadline_delta = grpc_time_averaged_stats_update_average(&shard->stats) * ADD_DEADLINE_SCALE; double deadline_delta = GPR_CLAMP(computed_deadline_delta, MIN_QUEUE_WINDOW_DURATION, MAX_QUEUE_WINDOW_DURATION); grpc_alarm *alarm, *next; /* Compute the new cap and put all alarms under it into the queue: */ shard->queue_deadline_cap = gpr_time_add( gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta)); for (alarm = shard->list.next; alarm != &shard->list; alarm = next) { next = alarm->next; if (gpr_time_cmp(alarm->deadline, shard->queue_deadline_cap) < 0) { list_remove(alarm); grpc_alarm_heap_add(&shard->heap, alarm); } } return !grpc_alarm_heap_is_empty(&shard->heap); } /* This pops the next non-cancelled alarm with deadline <= now from the queue, or returns NULL if there isn't one. REQUIRES: shard->mu locked */ static grpc_alarm *pop_one(shard_type *shard, gpr_timespec now) { grpc_alarm *alarm; for (;;) { if (grpc_alarm_heap_is_empty(&shard->heap)) { if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL; if (!refill_queue(shard, now)) return NULL; } alarm = grpc_alarm_heap_top(&shard->heap); if (gpr_time_cmp(alarm->deadline, now) > 0) return NULL; alarm->triggered = 1; grpc_alarm_heap_pop(&shard->heap); return alarm; } } /* REQUIRES: shard->mu unlocked */ static size_t pop_alarms(shard_type *shard, gpr_timespec now, grpc_alarm **alarms, size_t max_alarms, gpr_timespec *new_min_deadline) { size_t n = 0; grpc_alarm *alarm; gpr_mu_lock(&shard->mu); while (n < max_alarms && (alarm = pop_one(shard, now))) { alarms[n++] = alarm; } *new_min_deadline = compute_min_deadline(shard); gpr_mu_unlock(&shard->mu); return n; } static int run_some_expired_alarms(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next, int success) { size_t n = 0; size_t i; grpc_alarm *alarms[MAX_ALARMS_PER_CHECK]; /* TODO(ctiller): verify that there are any alarms (atomically) here */ if (gpr_mu_trylock(&g_checker_mu)) { gpr_mu_lock(&g_mu); while (n < MAX_ALARMS_PER_CHECK && gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) { gpr_timespec new_min_deadline; /* For efficiency, we pop as many available alarms as we can from the shard. This may violate perfect alarm deadline ordering, but that shouldn't be a big deal because we don't make ordering guarantees. */ n += pop_alarms(g_shard_queue[0], now, alarms + n, MAX_ALARMS_PER_CHECK - n, &new_min_deadline); /* An grpc_alarm_init() on the shard could intervene here, adding a new alarm that is earlier than new_min_deadline. However, grpc_alarm_init() will block on the master_lock before it can call set_min_deadline, so this one will complete first and then the AddAlarm will reduce the min_deadline (perhaps unnecessarily). */ g_shard_queue[0]->min_deadline = new_min_deadline; note_deadline_change(g_shard_queue[0]); } if (next) { *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline); } gpr_mu_unlock(&g_mu); gpr_mu_unlock(&g_checker_mu); } if (n && drop_mu) { gpr_mu_unlock(drop_mu); } for (i = 0; i < n; i++) { alarms[i]->cb(alarms[i]->cb_arg, success); } if (n && drop_mu) { gpr_mu_lock(drop_mu); } return n; } int grpc_alarm_check(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next) { GPR_ASSERT(now.clock_type == g_clock_type); return run_some_expired_alarms( drop_mu, now, next, gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0); } gpr_timespec grpc_alarm_list_next_timeout(void) { gpr_timespec out; gpr_mu_lock(&g_mu); out = g_shard_queue[0]->min_deadline; gpr_mu_unlock(&g_mu); return out; } grpc-0.11.1/src/core/iomgr/tcp_server.h0000644000175000017500000000665012600663151020107 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H #define GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H #include "src/core/iomgr/endpoint.h" /* Forward decl of grpc_tcp_server */ typedef struct grpc_tcp_server grpc_tcp_server; /* New server callback: tcp is the newly connected tcp connection */ typedef void (*grpc_tcp_server_cb)(void *arg, grpc_endpoint *ep); /* Create a server, initially not bound to any ports */ grpc_tcp_server *grpc_tcp_server_create(void); /* Start listening to bound ports */ void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset **pollsets, size_t pollset_count, grpc_tcp_server_cb cb, void *cb_arg); /* Add a port to the server, returning port number on success, or negative on failure. The :: and 0.0.0.0 wildcard addresses are treated identically, accepting both IPv4 and IPv6 connections, but :: is the preferred style. This usually creates one socket, but possibly two on systems which support IPv6, but not dualstack sockets. For raw access to the underlying sockets, see grpc_tcp_server_get_fd(). */ /* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle all of the multiple socket port matching logic in one place */ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, int addr_len); /* Returns the file descriptor of the Nth listening socket on this server, or -1 if the index is out of bounds. The file descriptor remains owned by the server, and will be cleaned up when grpc_tcp_server_destroy is called. */ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index); void grpc_tcp_server_destroy(grpc_tcp_server *server, void (*shutdown_done)(void *shutdown_done_arg), void *shutdown_done_arg); #endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */ grpc-0.11.1/src/core/iomgr/pollset_set.h0000644000175000017500000000477112600663151020272 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H #include "src/core/iomgr/pollset.h" /* A grpc_pollset_set is a set of pollsets that are interested in an action. Adding a pollset to a pollset_set automatically adds any fd's (etc) that have been registered with the set_set to that pollset. Registering fd's automatically adds them to all current pollsets. */ #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/pollset_set_posix.h" #endif #ifdef GPR_WIN32 #include "src/core/iomgr/pollset_set_windows.h" #endif void grpc_pollset_set_init(grpc_pollset_set *pollset_set); void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set); void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set, grpc_pollset *pollset); void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set, grpc_pollset *pollset); #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */ grpc-0.11.1/src/core/iomgr/wakeup_fd_posix.c0000644000175000017500000000511512600663151021110 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_WAKEUP_FD #include "src/core/iomgr/wakeup_fd_posix.h" #include "src/core/iomgr/wakeup_fd_pipe.h" #include static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL; void grpc_wakeup_fd_global_init(void) { if (grpc_specialized_wakeup_fd_vtable.check_availability()) { wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable; } else { wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable; } } void grpc_wakeup_fd_global_init_force_fallback(void) { wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable; } void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; } void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) { wakeup_fd_vtable->init(fd_info); } void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) { wakeup_fd_vtable->consume(fd_info); } void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) { wakeup_fd_vtable->wakeup(fd_info); } void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) { wakeup_fd_vtable->destroy(fd_info); } #endif /* GPR_POSIX_WAKEUP_FD */ grpc-0.11.1/src/core/iomgr/endpoint_pair.h0000644000175000017500000000371512600663151020565 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H #define GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H #include "src/core/iomgr/endpoint.h" typedef struct { grpc_endpoint *client; grpc_endpoint *server; } grpc_endpoint_pair; grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size); #endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */ grpc-0.11.1/src/core/iomgr/socket_utils_linux.c0000644000175000017500000000373212600663151021653 0ustar apollockapollock/* * * 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 #ifdef GPR_LINUX_SOCKETUTILS #include "src/core/iomgr/socket_utils_posix.h" #include #include int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int nonblock, int cloexec) { int flags = 0; flags |= nonblock ? SOCK_NONBLOCK : 0; flags |= cloexec ? SOCK_CLOEXEC : 0; return accept4(sockfd, addr, addrlen, flags); } #endif grpc-0.11.1/src/core/iomgr/sockaddr_win32.h0000644000175000017500000000362712600663151020550 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H #define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H #include #include #include #ifdef __MINGW32__ /* mingw seems to be missing that definition. */ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); #endif #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */ grpc-0.11.1/src/core/iomgr/resolve_address.h0000644000175000017500000000550412600663151021114 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H #define GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H #include #define GRPC_MAX_SOCKADDR_SIZE 128 typedef struct { char addr[GRPC_MAX_SOCKADDR_SIZE]; int len; } grpc_resolved_address; typedef struct { size_t naddrs; grpc_resolved_address *addrs; } grpc_resolved_addresses; /* Async result callback: On success: addresses is the result, and the callee must call grpc_resolved_addresses_destroy when it's done with them On failure: addresses is NULL */ typedef void (*grpc_resolve_cb)(void *arg, grpc_resolved_addresses *addresses); /* Asynchronously resolve addr. Use default_port if a port isn't designated in addr, otherwise use the port in addr. */ /* TODO(ctiller): add a timeout here */ void grpc_resolve_address(const char *addr, const char *default_port, grpc_resolve_cb cb, void *arg); /* Destroy resolved addresses */ void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses); /* Resolve addr in a blocking fashion. Returns NULL on failure. On success, result must be freed with grpc_resolved_addresses_destroy. */ grpc_resolved_addresses *grpc_blocking_resolve_address( const char *addr, const char *default_port); #endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */ grpc-0.11.1/src/core/iomgr/tcp_windows.h0000644000175000017500000000441112600663151020264 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H #define GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H /* Low level TCP "bottom half" implementation, for use by transports built on top of a TCP connection. Note that this file does not (yet) include APIs for creating the socket in the first place. All calls passing slice transfer ownership of a slice refcount unless otherwise specified. */ #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/socket_windows.h" /* Create a tcp endpoint given a winsock handle. * Takes ownership of the handle. */ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string); int grpc_tcp_prepare_socket(SOCKET sock); #endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H */ grpc-0.11.1/src/core/iomgr/pollset_multipoller_with_epoll.c0000644000175000017500000002055312600663151024264 0ustar apollockapollock/* * * 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 #ifdef GPR_LINUX_MULTIPOLL_WITH_EPOLL #include #include #include #include #include #include "src/core/iomgr/fd_posix.h" #include #include typedef struct wakeup_fd_hdl { grpc_wakeup_fd wakeup_fd; struct wakeup_fd_hdl *next; } wakeup_fd_hdl; typedef struct { grpc_pollset *pollset; grpc_fd *fd; grpc_iomgr_closure closure; } delayed_add; typedef struct { int epoll_fd; wakeup_fd_hdl *free_wakeup_fds; } pollset_hdr; static void finally_add_fd(grpc_pollset *pollset, grpc_fd *fd) { pollset_hdr *h = pollset->data.ptr; struct epoll_event ev; int err; grpc_fd_watcher watcher; /* We pretend to be polling whilst adding an fd to keep the fd from being closed during the add. This may result in a spurious wakeup being assigned to this pollset whilst adding, but that should be benign. */ GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, 0, 0, &watcher) == 0); if (watcher.fd != NULL) { ev.events = EPOLLIN | EPOLLOUT | EPOLLET; ev.data.ptr = fd; err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev); if (err < 0) { /* FDs may be added to a pollset multiple times, so EEXIST is normal. */ if (errno != EEXIST) { gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd, strerror(errno)); } } } grpc_fd_end_poll(&watcher, 0, 0); } static void perform_delayed_add(void *arg, int iomgr_status) { delayed_add *da = arg; int do_shutdown_cb = 0; if (!grpc_fd_is_orphaned(da->fd)) { finally_add_fd(da->pollset, da->fd); } gpr_mu_lock(&da->pollset->mu); da->pollset->in_flight_cbs--; if (da->pollset->shutting_down) { /* We don't care about this pollset anymore. */ if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) { da->pollset->called_shutdown = 1; do_shutdown_cb = 1; } } gpr_mu_unlock(&da->pollset->mu); GRPC_FD_UNREF(da->fd, "delayed_add"); if (do_shutdown_cb) { da->pollset->shutdown_done_cb(da->pollset->shutdown_done_arg); } gpr_free(da); } static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd, int and_unlock_pollset) { if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); finally_add_fd(pollset, fd); } else { delayed_add *da = gpr_malloc(sizeof(*da)); da->pollset = pollset; da->fd = fd; GRPC_FD_REF(fd, "delayed_add"); grpc_iomgr_closure_init(&da->closure, perform_delayed_add, da); pollset->in_flight_cbs++; grpc_iomgr_add_callback(&da->closure); } } static void multipoll_with_epoll_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd, int and_unlock_pollset) { pollset_hdr *h = pollset->data.ptr; int err; if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); } /* Note that this can race with concurrent poll, but that should be fine since * at worst it creates a spurious read event on a reused grpc_fd object. */ err = epoll_ctl(h->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL); if (err < 0) { gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd->fd, strerror(errno)); } } /* TODO(klempner): We probably want to turn this down a bit */ #define GRPC_EPOLL_MAX_EVENTS 1000 static void multipoll_with_epoll_pollset_maybe_work( grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline, gpr_timespec now, int allow_synchronous_callback) { struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; int ep_rv; int poll_rv; pollset_hdr *h = pollset->data.ptr; int timeout_ms; struct pollfd pfds[2]; /* If you want to ignore epoll's ability to sanely handle parallel pollers, * for a more apples-to-apples performance comparison with poll, add a * if (pollset->counter != 0) { return 0; } * here. */ gpr_mu_unlock(&pollset->mu); timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now); pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd); pfds[0].events = POLLIN; pfds[0].revents = 0; pfds[1].fd = h->epoll_fd; pfds[1].events = POLLIN; pfds[1].revents = 0; poll_rv = grpc_poll_function(pfds, 2, timeout_ms); if (poll_rv < 0) { if (errno != EINTR) { gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); } } else if (poll_rv == 0) { /* do nothing */ } else { if (pfds[0].revents) { grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd); } if (pfds[1].revents) { do { ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); if (ep_rv < 0) { if (errno != EINTR) { gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno)); } } else { int i; for (i = 0; i < ep_rv; ++i) { grpc_fd *fd = ep_ev[i].data.ptr; /* TODO(klempner): We might want to consider making err and pri * separate events */ int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); int read = ep_ev[i].events & (EPOLLIN | EPOLLPRI); int write = ep_ev[i].events & EPOLLOUT; if (read || cancel) { grpc_fd_become_readable(fd, allow_synchronous_callback); } if (write || cancel) { grpc_fd_become_writable(fd, allow_synchronous_callback); } } } } while (ep_rv == GRPC_EPOLL_MAX_EVENTS); } } gpr_mu_lock(&pollset->mu); } static void multipoll_with_epoll_pollset_finish_shutdown( grpc_pollset *pollset) {} static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) { pollset_hdr *h = pollset->data.ptr; close(h->epoll_fd); gpr_free(h); } static const grpc_pollset_vtable multipoll_with_epoll_pollset = { multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd, multipoll_with_epoll_pollset_maybe_work, multipoll_with_epoll_pollset_finish_shutdown, multipoll_with_epoll_pollset_destroy}; static void epoll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds, size_t nfds) { size_t i; pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); pollset->vtable = &multipoll_with_epoll_pollset; pollset->data.ptr = h; h->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (h->epoll_fd < 0) { /* TODO(klempner): Fall back to poll here, especially on ENOSYS */ gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno)); abort(); } for (i = 0; i < nfds; i++) { multipoll_with_epoll_pollset_add_fd(pollset, fds[i], 0); } } grpc_platform_become_multipoller_type grpc_platform_become_multipoller = epoll_become_multipoller; #endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */ grpc-0.11.1/src/core/iomgr/socket_windows.h0000644000175000017500000001157012600663151020772 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H #define GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H #include #include #include #include #include "src/core/iomgr/iomgr_internal.h" /* This holds the data for an outstanding read or write on a socket. The mutex to protect the concurrent access to that data is the one inside the winsocket wrapper. */ typedef struct grpc_winsocket_callback_info { /* This is supposed to be a WSAOVERLAPPED, but in order to get that definition, we need to include ws2tcpip.h, which needs to be included from the top, otherwise it'll clash with a previous inclusion of windows.h that in turns includes winsock.h. If anyone knows a way to do it properly, feel free to send a patch. */ OVERLAPPED overlapped; /* The callback information for the pending operation. May be empty if the caller hasn't registered a callback yet. */ void (*cb)(void *opaque, int success); void *opaque; /* A boolean to describe if the IO Completion Port got a notification for that operation. This will happen if the operation completed before the called had time to register a callback. We could avoid that behavior altogether by forcing the caller to always register its callback before proceeding queue an operation, but it is frequent for an IO Completion Port to trigger quickly. This way we avoid a context switch for calling the callback. We also simplify the read / write operations to avoid having to hold a mutex for a long amount of time. */ int has_pending_iocp; /* The results of the overlapped operation. */ DWORD bytes_transfered; int wsa_error; } grpc_winsocket_callback_info; /* This is a wrapper to a Windows socket. A socket can have one outstanding read, and one outstanding write. Doing an asynchronous accept means waiting for a read operation. Doing an asynchronous connect means waiting for a write operation. These are completely arbitrary ties between the operation and the kind of event, because we can have one overlapped per pending operation, whichever its nature is. So we could have more dedicated pending operation callbacks for connect and listen. But given the scope of listen and accept, we don't need to go to that extent and waste memory. Also, this is closer to what happens in posix world. */ typedef struct grpc_winsocket { SOCKET socket; grpc_winsocket_callback_info write_info; grpc_winsocket_callback_info read_info; gpr_mu state_mu; /* You can't add the same socket twice to the same IO Completion Port. This prevents that. */ int added_to_iocp; grpc_iomgr_closure shutdown_closure; /* A label for iomgr to track outstanding objects */ grpc_iomgr_object iomgr_object; } grpc_winsocket; /* Create a wrapped windows handle. This takes ownership of it, meaning that it will be responsible for closing it. */ grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name); /* Initiate an asynchronous shutdown of the socket. Will call off any pending operation to cancel them. */ void grpc_winsocket_shutdown(grpc_winsocket *socket); /* Destroy a socket. Should only be called if there's no pending operation. */ void grpc_winsocket_destroy(grpc_winsocket *socket); #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */ grpc-0.11.1/src/core/iomgr/tcp_client_posix.c0000644000175000017500000002020512600663151021264 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/tcp_client.h" #include #include #include #include #include "src/core/iomgr/alarm.h" #include "src/core/iomgr/iomgr_posix.h" #include "src/core/iomgr/pollset_posix.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_utils_posix.h" #include "src/core/iomgr/tcp_posix.h" #include "src/core/support/string.h" #include #include #include #include typedef struct { void (*cb)(void *arg, grpc_endpoint *tcp); void *cb_arg; gpr_mu mu; grpc_fd *fd; gpr_timespec deadline; grpc_alarm alarm; int refs; grpc_iomgr_closure write_closure; grpc_pollset_set *interested_parties; char *addr_str; } async_connect; static int prepare_socket(const struct sockaddr *addr, int fd) { if (fd < 0) { goto error; } if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1)) || !grpc_set_socket_no_sigpipe_if_possible(fd)) { gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, strerror(errno)); goto error; } return 1; error: if (fd >= 0) { close(fd); } return 0; } static void tc_on_alarm(void *acp, int success) { int done; async_connect *ac = acp; gpr_mu_lock(&ac->mu); if (ac->fd != NULL) { grpc_fd_shutdown(ac->fd); } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); gpr_free(ac); } } static void on_writable(void *acp, int success) { async_connect *ac = acp; int so_error = 0; socklen_t so_error_size; int err; int done; grpc_endpoint *ep = NULL; void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb; void *cb_arg = ac->cb_arg; grpc_fd *fd; gpr_mu_lock(&ac->mu); GPR_ASSERT(ac->fd); fd = ac->fd; ac->fd = NULL; gpr_mu_unlock(&ac->mu); grpc_alarm_cancel(&ac->alarm); gpr_mu_lock(&ac->mu); if (success) { do { so_error_size = sizeof(so_error); err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size); } while (err < 0 && errno == EINTR); if (err < 0) { gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno)); goto finish; } else if (so_error != 0) { if (so_error == ENOBUFS) { /* We will get one of these errors if we have run out of memory in the kernel for the data structures allocated when you connect a socket. If this happens it is very likely that if we wait a little bit then try again the connection will work (since other programs or this program will close their network connections and free up memory). This does _not_ indicate that there is anything wrong with the server we are connecting to, this is a local problem. If you are looking at this code, then chances are that your program or another program on the same computer opened too many network connections. The "easy" fix: don't do that! */ gpr_log(GPR_ERROR, "kernel out of buffers"); gpr_mu_unlock(&ac->mu); grpc_fd_notify_on_write(fd, &ac->write_closure); return; } else { switch (so_error) { case ECONNREFUSED: gpr_log(GPR_ERROR, "socket error: connection refused"); break; default: gpr_log(GPR_ERROR, "socket error: %d", so_error); break; } goto finish; } } else { grpc_pollset_set_del_fd(ac->interested_parties, fd); ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str); fd = NULL; goto finish; } } else { gpr_log(GPR_ERROR, "on_writable failed during connect"); goto finish; } abort(); finish: if (fd != NULL) { grpc_pollset_set_del_fd(ac->interested_parties, fd); grpc_fd_orphan(fd, NULL, "tcp_client_orphan"); fd = NULL; } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); gpr_free(ac); } cb(cb_arg, ep); } void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep), void *arg, grpc_pollset_set *interested_parties, const struct sockaddr *addr, int addr_len, gpr_timespec deadline) { int fd; grpc_dualstack_mode dsmode; int err; async_connect *ac; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in addr4_copy; grpc_fd *fdobj; char *name; char *addr_str; /* Use dualstack sockets where available. */ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4) { /* If we got an AF_INET socket, map the address back to IPv4. */ GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } if (!prepare_socket(addr, fd)) { cb(arg, NULL); return; } do { err = connect(fd, addr, addr_len); } while (err < 0 && errno == EINTR); addr_str = grpc_sockaddr_to_uri(addr); gpr_asprintf(&name, "tcp-client:%s", addr_str); fdobj = grpc_fd_create(fd, name); if (err >= 0) { cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str)); goto done; } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno)); grpc_fd_orphan(fdobj, NULL, "tcp_client_connect_error"); cb(arg, NULL); goto done; } grpc_pollset_set_add_fd(interested_parties, fdobj); ac = gpr_malloc(sizeof(async_connect)); ac->cb = cb; ac->cb_arg = arg; ac->fd = fdobj; ac->interested_parties = interested_parties; ac->addr_str = addr_str; addr_str = NULL; gpr_mu_init(&ac->mu); ac->refs = 2; ac->write_closure.cb = on_writable; ac->write_closure.cb_arg = ac; gpr_mu_lock(&ac->mu); grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); done: gpr_free(name); gpr_free(addr_str); } #endif grpc-0.11.1/src/core/iomgr/iomgr_internal.h0000644000175000017500000000436412600663151020744 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H #define GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H #include "src/core/iomgr/iomgr.h" #include typedef struct grpc_iomgr_object { char *name; struct grpc_iomgr_object *next; struct grpc_iomgr_object *prev; } grpc_iomgr_object; int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success); void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *iocb, int success); void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name); void grpc_iomgr_unregister_object(grpc_iomgr_object *obj); void grpc_iomgr_platform_init(void); void grpc_iomgr_platform_shutdown(void); #endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */ grpc-0.11.1/src/core/iomgr/tcp_client.h0000644000175000017500000000464112600663151020055 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H #define GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/pollset_set.h" #include "src/core/iomgr/sockaddr.h" #include /* Asynchronously connect to an address (specified as (addr, len)), and call cb with arg and the completed connection when done (or call cb with arg and NULL on failure). interested_parties points to a set of pollsets that would be interested in this connection being established (in order to continue their work) */ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp), void *arg, grpc_pollset_set *interested_parties, const struct sockaddr *addr, int addr_len, gpr_timespec deadline); #endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H */ grpc-0.11.1/src/core/iomgr/pollset_set_posix.c0000644000175000017500000001116012600663151021475 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include #include #include #include #include "src/core/iomgr/pollset_set.h" void grpc_pollset_set_init(grpc_pollset_set *pollset_set) { memset(pollset_set, 0, sizeof(*pollset_set)); gpr_mu_init(&pollset_set->mu); } void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) { size_t i; gpr_mu_destroy(&pollset_set->mu); for (i = 0; i < pollset_set->fd_count; i++) { GRPC_FD_UNREF(pollset_set->fds[i], "pollset"); } gpr_free(pollset_set->pollsets); gpr_free(pollset_set->fds); } void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set, grpc_pollset *pollset) { size_t i, j; gpr_mu_lock(&pollset_set->mu); if (pollset_set->pollset_count == pollset_set->pollset_capacity) { pollset_set->pollset_capacity = GPR_MAX(8, 2 * pollset_set->pollset_capacity); pollset_set->pollsets = gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity * sizeof(*pollset_set->pollsets)); } pollset_set->pollsets[pollset_set->pollset_count++] = pollset; for (i = 0, j = 0; i < pollset_set->fd_count; i++) { if (grpc_fd_is_orphaned(pollset_set->fds[i])) { GRPC_FD_UNREF(pollset_set->fds[i], "pollset"); } else { grpc_pollset_add_fd(pollset, pollset_set->fds[i]); pollset_set->fds[j++] = pollset_set->fds[i]; } } pollset_set->fd_count = j; gpr_mu_unlock(&pollset_set->mu); } void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set, grpc_pollset *pollset) { size_t i; gpr_mu_lock(&pollset_set->mu); for (i = 0; i < pollset_set->pollset_count; i++) { if (pollset_set->pollsets[i] == pollset) { pollset_set->pollset_count--; GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i], pollset_set->pollsets[pollset_set->pollset_count]); break; } } gpr_mu_unlock(&pollset_set->mu); } void grpc_pollset_set_add_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) { size_t i; gpr_mu_lock(&pollset_set->mu); if (pollset_set->fd_count == pollset_set->fd_capacity) { pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity); pollset_set->fds = gpr_realloc( pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds)); } GRPC_FD_REF(fd, "pollset_set"); pollset_set->fds[pollset_set->fd_count++] = fd; for (i = 0; i < pollset_set->pollset_count; i++) { grpc_pollset_add_fd(pollset_set->pollsets[i], fd); } gpr_mu_unlock(&pollset_set->mu); } void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) { size_t i; gpr_mu_lock(&pollset_set->mu); for (i = 0; i < pollset_set->fd_count; i++) { if (pollset_set->fds[i] == fd) { pollset_set->fd_count--; GPR_SWAP(grpc_fd *, pollset_set->fds[i], pollset_set->fds[pollset_set->fd_count]); GRPC_FD_UNREF(fd, "pollset_set"); break; } } gpr_mu_unlock(&pollset_set->mu); } #endif /* GPR_POSIX_SOCKET */ grpc-0.11.1/src/core/iomgr/pollset_posix.h0000644000175000017500000001203712600663151020633 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_POSIX_H #include #include #include "src/core/iomgr/wakeup_fd_posix.h" typedef struct grpc_pollset_vtable grpc_pollset_vtable; /* forward declare only in this file to avoid leaking impl details via pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not use the struct tag */ struct grpc_fd; typedef struct grpc_pollset_worker { grpc_wakeup_fd wakeup_fd; struct grpc_pollset_worker *next; struct grpc_pollset_worker *prev; } grpc_pollset_worker; typedef struct grpc_pollset { /* pollsets under posix can mutate representation as fds are added and removed. For example, we may choose a poll() based implementation on linux for few fds, and an epoll() based implementation for many fds */ const grpc_pollset_vtable *vtable; gpr_mu mu; grpc_pollset_worker root_worker; int in_flight_cbs; int shutting_down; int called_shutdown; int kicked_without_pollers; void (*shutdown_done_cb)(void *arg); void *shutdown_done_arg; union { int fd; void *ptr; } data; } grpc_pollset; struct grpc_pollset_vtable { void (*add_fd)(grpc_pollset *pollset, struct grpc_fd *fd, int and_unlock_pollset); void (*del_fd)(grpc_pollset *pollset, struct grpc_fd *fd, int and_unlock_pollset); void (*maybe_work)(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline, gpr_timespec now, int allow_synchronous_callback); void (*finish_shutdown)(grpc_pollset *pollset); void (*destroy)(grpc_pollset *pollset); }; #define GRPC_POLLSET_MU(pollset) (&(pollset)->mu) /* Add an fd to a pollset */ void grpc_pollset_add_fd(grpc_pollset *pollset, struct grpc_fd *fd); /* Force remove an fd from a pollset (normally they are removed on the next poll after an fd is orphaned) */ void grpc_pollset_del_fd(grpc_pollset *pollset, struct grpc_fd *fd); /* Returns the fd to listen on for kicks */ int grpc_kick_read_fd(grpc_pollset *p); /* Call after polling has been kicked to leave the kicked state */ void grpc_kick_drain(grpc_pollset *p); /* Convert a timespec to milliseconds: - very small or negative poll times are clamped to zero to do a non-blocking poll (which becomes spin polling) - other small values are rounded up to one millisecond - longer than a millisecond polls are rounded up to the next nearest millisecond to avoid spinning - infinite timeouts are converted to -1 */ int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now); /* turn a pollset into a multipoller: platform specific */ typedef void (*grpc_platform_become_multipoller_type)(grpc_pollset *pollset, struct grpc_fd **fds, size_t fd_count); extern grpc_platform_become_multipoller_type grpc_platform_become_multipoller; void grpc_poll_become_multipoller(grpc_pollset *pollset, struct grpc_fd **fds, size_t fd_count); /* Return 1 if the pollset has active threads in grpc_pollset_work (pollset must * be locked) */ int grpc_pollset_has_workers(grpc_pollset *pollset); /* override to allow tests to hook poll() usage */ typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int); extern grpc_poll_function_type grpc_poll_function; #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_POSIX_H */ grpc-0.11.1/src/core/iomgr/iomgr.c0000644000175000017500000002132412600663151017036 0ustar apollockapollock/* * * 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/iomgr/iomgr.h" #include #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/alarm_internal.h" #include "src/core/support/string.h" #include #include #include #include #include static gpr_mu g_mu; static gpr_cv g_rcv; static grpc_iomgr_closure *g_cbs_head = NULL; static grpc_iomgr_closure *g_cbs_tail = NULL; static int g_shutdown; static gpr_event g_background_callback_executor_done; static grpc_iomgr_object g_root_object; /* Execute followup callbacks continuously. Other threads may check in and help during pollset_work() */ static void background_callback_executor(void *ignored) { gpr_mu_lock(&g_mu); while (!g_shutdown) { gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); gpr_timespec short_deadline = gpr_time_add( gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(100, GPR_TIMESPAN)); if (g_cbs_head) { grpc_iomgr_closure *closure = g_cbs_head; g_cbs_head = closure->next; if (!g_cbs_head) g_cbs_tail = NULL; gpr_mu_unlock(&g_mu); closure->cb(closure->cb_arg, closure->success); gpr_mu_lock(&g_mu); } else if (grpc_alarm_check(&g_mu, gpr_now(GPR_CLOCK_MONOTONIC), &deadline)) { } else { gpr_mu_unlock(&g_mu); gpr_sleep_until(gpr_time_min(short_deadline, deadline)); gpr_mu_lock(&g_mu); } } gpr_mu_unlock(&g_mu); gpr_event_set(&g_background_callback_executor_done, (void *)1); } void grpc_kick_poller(void) { /* Empty. The background callback executor polls periodically. The activity * the kicker is trying to draw the executor's attention to will be picked up * either by one of the periodic wakeups or by one of the polling application * threads. */ } void grpc_iomgr_init(void) { gpr_thd_id id; g_shutdown = 0; gpr_mu_init(&g_mu); gpr_cv_init(&g_rcv); grpc_alarm_list_init(gpr_now(GPR_CLOCK_MONOTONIC)); g_root_object.next = g_root_object.prev = &g_root_object; g_root_object.name = "root"; grpc_iomgr_platform_init(); gpr_event_init(&g_background_callback_executor_done); gpr_thd_new(&id, background_callback_executor, NULL, NULL); } static size_t count_objects(void) { grpc_iomgr_object *obj; size_t n = 0; for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { n++; } return n; } static void dump_objects(const char *kind) { grpc_iomgr_object *obj; for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { gpr_log(GPR_DEBUG, "%s OBJECT: %s %p", kind, obj->name, obj); } } void grpc_iomgr_shutdown(void) { grpc_iomgr_closure *closure; gpr_timespec shutdown_deadline = gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN)); gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME); gpr_mu_lock(&g_mu); g_shutdown = 1; while (g_cbs_head != NULL || g_root_object.next != &g_root_object) { if (gpr_time_cmp( gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time), gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { if (g_cbs_head != NULL && g_root_object.next != &g_root_object) { gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed and executing " "final callbacks", count_objects()); } else if (g_cbs_head != NULL) { gpr_log(GPR_DEBUG, "Executing final iomgr callbacks"); } else { gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed", count_objects()); } last_warning_time = gpr_now(GPR_CLOCK_REALTIME); } if (g_cbs_head) { do { closure = g_cbs_head; g_cbs_head = closure->next; if (!g_cbs_head) g_cbs_tail = NULL; gpr_mu_unlock(&g_mu); closure->cb(closure->cb_arg, 0); gpr_mu_lock(&g_mu); } while (g_cbs_head); continue; } if (grpc_alarm_check(&g_mu, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL)) { continue; } if (g_root_object.next != &g_root_object) { int timeout = 0; while (g_cbs_head == NULL) { gpr_timespec short_deadline = gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN)); if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) { if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) { timeout = 1; break; } } } if (timeout) { gpr_log(GPR_DEBUG, "Failed to free %d iomgr objects before shutdown deadline: " "memory leaks are likely", count_objects()); dump_objects("LEAKED"); break; } } } gpr_mu_unlock(&g_mu); grpc_kick_poller(); gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future(GPR_CLOCK_REALTIME)); grpc_alarm_list_shutdown(); grpc_iomgr_platform_shutdown(); gpr_mu_destroy(&g_mu); gpr_cv_destroy(&g_rcv); } void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) { obj->name = gpr_strdup(name); gpr_mu_lock(&g_mu); obj->next = &g_root_object; obj->prev = g_root_object.prev; obj->next->prev = obj->prev->next = obj; gpr_mu_unlock(&g_mu); } void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) { gpr_mu_lock(&g_mu); obj->next->prev = obj->prev; obj->prev->next = obj->next; gpr_cv_signal(&g_rcv); gpr_mu_unlock(&g_mu); gpr_free(obj->name); } void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb, void *cb_arg) { closure->cb = cb; closure->cb_arg = cb_arg; closure->next = NULL; } static void assert_not_scheduled_locked(grpc_iomgr_closure *closure) { #ifndef NDEBUG grpc_iomgr_closure *c; for (c = g_cbs_head; c; c = c->next) { GPR_ASSERT(c != closure); } #endif } void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *closure, int success) { closure->success = success; GPR_ASSERT(closure->cb); gpr_mu_lock(&g_mu); assert_not_scheduled_locked(closure); closure->next = NULL; if (!g_cbs_tail) { g_cbs_head = g_cbs_tail = closure; } else { g_cbs_tail->next = closure; g_cbs_tail = closure; } if (g_shutdown) { gpr_cv_signal(&g_rcv); } gpr_mu_unlock(&g_mu); } void grpc_iomgr_add_callback(grpc_iomgr_closure *closure) { grpc_iomgr_add_delayed_callback(closure, 1 /* GPR_TRUE */); } int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) { int n = 0; gpr_mu *retake_mu = NULL; grpc_iomgr_closure *closure; for (;;) { /* check for new work */ if (!gpr_mu_trylock(&g_mu)) { break; } closure = g_cbs_head; if (!closure) { gpr_mu_unlock(&g_mu); break; } g_cbs_head = closure->next; if (!g_cbs_head) g_cbs_tail = NULL; gpr_mu_unlock(&g_mu); /* if we have a mutex to drop, do so before executing work */ if (drop_mu) { gpr_mu_unlock(drop_mu); retake_mu = drop_mu; drop_mu = NULL; } closure->cb(closure->cb_arg, success && closure->success); n++; } if (retake_mu) { gpr_mu_lock(retake_mu); } return n; } grpc-0.11.1/src/core/iomgr/tcp_posix.h0000644000175000017500000000453412600663151017742 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H /* Low level TCP "bottom half" implementation, for use by transports built on top of a TCP connection. Note that this file does not (yet) include APIs for creating the socket in the first place. All calls passing slice transfer ownership of a slice refcount unless otherwise specified. */ #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/fd_posix.h" #define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 extern int grpc_tcp_trace; /* Create a tcp endpoint given a file desciptor and a read slice size. Takes ownership of fd. */ grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size, const char *peer_string); #endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */ grpc-0.11.1/src/core/iomgr/fd_posix.c0000644000175000017500000003560112600663151017537 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/fd_posix.h" #include #include #include #include #include #include enum descriptor_state { NOT_READY = 0, READY = 1 }; /* or a pointer to a closure to call */ /* We need to keep a freelist not because of any concerns of malloc performance * but instead so that implementations with multiple threads in (for example) * epoll_wait deal with the race between pollset removal and incoming poll * notifications. * * The problem is that the poller ultimately holds a reference to this * object, so it is very difficult to know when is safe to free it, at least * without some expensive synchronization. * * If we keep the object freelisted, in the worst case losing this race just * becomes a spurious read notification on a reused fd. */ /* TODO(klempner): We could use some form of polling generation count to know * when these are safe to free. */ /* TODO(klempner): Consider disabling freelisting if we don't have multiple * threads in poll on the same fd */ /* TODO(klempner): Batch these allocations to reduce fragmentation */ static grpc_fd *fd_freelist = NULL; static gpr_mu fd_freelist_mu; static void freelist_fd(grpc_fd *fd) { gpr_mu_lock(&fd_freelist_mu); fd->freelist_next = fd_freelist; fd_freelist = fd; grpc_iomgr_unregister_object(&fd->iomgr_object); gpr_mu_unlock(&fd_freelist_mu); } static grpc_fd *alloc_fd(int fd) { grpc_fd *r = NULL; gpr_mu_lock(&fd_freelist_mu); if (fd_freelist != NULL) { r = fd_freelist; fd_freelist = fd_freelist->freelist_next; } gpr_mu_unlock(&fd_freelist_mu); if (r == NULL) { r = gpr_malloc(sizeof(grpc_fd)); gpr_mu_init(&r->set_state_mu); gpr_mu_init(&r->watcher_mu); } gpr_atm_rel_store(&r->refst, 1); gpr_atm_rel_store(&r->readst, NOT_READY); gpr_atm_rel_store(&r->writest, NOT_READY); gpr_atm_rel_store(&r->shutdown, 0); r->fd = fd; r->inactive_watcher_root.next = r->inactive_watcher_root.prev = &r->inactive_watcher_root; r->freelist_next = NULL; r->read_watcher = r->write_watcher = NULL; r->on_done_closure = NULL; r->closed = 0; return r; } static void destroy(grpc_fd *fd) { gpr_mu_destroy(&fd->set_state_mu); gpr_mu_destroy(&fd->watcher_mu); gpr_free(fd); } #ifdef GRPC_FD_REF_COUNT_DEBUG #define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, int line) { gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); #else #define REF_BY(fd, n, reason) ref_by(fd, n) #define UNREF_BY(fd, n, reason) unref_by(fd, n) static void ref_by(grpc_fd *fd, int n) { #endif GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); } #ifdef GRPC_FD_REF_COUNT_DEBUG static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file, int line) { gpr_atm old; gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); #else static void unref_by(grpc_fd *fd, int n) { gpr_atm old; #endif old = gpr_atm_full_fetch_add(&fd->refst, -n); if (old == n) { freelist_fd(fd); } else { GPR_ASSERT(old > n); } } void grpc_fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } void grpc_fd_global_shutdown(void) { while (fd_freelist != NULL) { grpc_fd *fd = fd_freelist; fd_freelist = fd_freelist->freelist_next; destroy(fd); } gpr_mu_destroy(&fd_freelist_mu); } grpc_fd *grpc_fd_create(int fd, const char *name) { grpc_fd *r = alloc_fd(fd); grpc_iomgr_register_object(&r->iomgr_object, name); return r; } int grpc_fd_is_orphaned(grpc_fd *fd) { return (gpr_atm_acq_load(&fd->refst) & 1) == 0; } static void pollset_kick_locked(grpc_pollset *pollset) { gpr_mu_lock(GRPC_POLLSET_MU(pollset)); grpc_pollset_kick(pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(pollset)); } static void maybe_wake_one_watcher_locked(grpc_fd *fd) { if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) { pollset_kick_locked(fd->inactive_watcher_root.next->pollset); } else if (fd->read_watcher) { pollset_kick_locked(fd->read_watcher->pollset); } else if (fd->write_watcher) { pollset_kick_locked(fd->write_watcher->pollset); } } static void maybe_wake_one_watcher(grpc_fd *fd) { gpr_mu_lock(&fd->watcher_mu); maybe_wake_one_watcher_locked(fd); gpr_mu_unlock(&fd->watcher_mu); } static void wake_all_watchers_locked(grpc_fd *fd) { grpc_fd_watcher *watcher; for (watcher = fd->inactive_watcher_root.next; watcher != &fd->inactive_watcher_root; watcher = watcher->next) { pollset_kick_locked(watcher->pollset); } if (fd->read_watcher) { pollset_kick_locked(fd->read_watcher->pollset); } if (fd->write_watcher && fd->write_watcher != fd->read_watcher) { pollset_kick_locked(fd->write_watcher->pollset); } } static int has_watchers(grpc_fd *fd) { return fd->read_watcher != NULL || fd->write_watcher != NULL || fd->inactive_watcher_root.next != &fd->inactive_watcher_root; } void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done, const char *reason) { fd->on_done_closure = on_done; shutdown(fd->fd, SHUT_RDWR); REF_BY(fd, 1, reason); /* remove active status, but keep referenced */ gpr_mu_lock(&fd->watcher_mu); if (!has_watchers(fd)) { GPR_ASSERT(!fd->closed); fd->closed = 1; close(fd->fd); if (fd->on_done_closure) { grpc_iomgr_add_callback(fd->on_done_closure); } } else { wake_all_watchers_locked(fd); } gpr_mu_unlock(&fd->watcher_mu); UNREF_BY(fd, 2, reason); /* drop the reference */ } /* increment refcount by two to avoid changing the orphan bit */ #ifdef GRPC_FD_REF_COUNT_DEBUG void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) { ref_by(fd, 2, reason, file, line); } void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line) { unref_by(fd, 2, reason, file, line); } #else void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); } void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); } #endif static void process_callback(grpc_iomgr_closure *closure, int success, int allow_synchronous_callback) { if (allow_synchronous_callback) { closure->cb(closure->cb_arg, success); } else { grpc_iomgr_add_delayed_callback(closure, success); } } static void process_callbacks(grpc_iomgr_closure *callbacks, size_t n, int success, int allow_synchronous_callback) { size_t i; for (i = 0; i < n; i++) { process_callback(callbacks + i, success, allow_synchronous_callback); } } static void notify_on(grpc_fd *fd, gpr_atm *st, grpc_iomgr_closure *closure, int allow_synchronous_callback) { switch (gpr_atm_acq_load(st)) { case NOT_READY: /* There is no race if the descriptor is already ready, so we skip the interlocked op in that case. As long as the app doesn't try to set the same upcall twice (which it shouldn't) then oldval should never be anything other than READY or NOT_READY. We don't check for user error on the fast path. */ if (gpr_atm_rel_cas(st, NOT_READY, (gpr_intptr)closure)) { /* swap was successful -- the closure will run after the next set_ready call. NOTE: we don't have an ABA problem here, since we should never have concurrent calls to the same notify_on function. */ maybe_wake_one_watcher(fd); return; } /* swap was unsuccessful due to an intervening set_ready call. Fall through to the READY code below */ case READY: GPR_ASSERT(gpr_atm_no_barrier_load(st) == READY); gpr_atm_rel_store(st, NOT_READY); process_callback(closure, !gpr_atm_acq_load(&fd->shutdown), allow_synchronous_callback); return; default: /* WAITING */ /* upcallptr was set to a different closure. This is an error! */ gpr_log(GPR_ERROR, "User called a notify_on function with a previous callback still " "pending"); abort(); } gpr_log(GPR_ERROR, "Corrupt memory in &st->state"); abort(); } static void set_ready_locked(gpr_atm *st, grpc_iomgr_closure **callbacks, size_t *ncallbacks) { gpr_intptr state = gpr_atm_acq_load(st); switch (state) { case READY: /* duplicate ready, ignore */ return; case NOT_READY: if (gpr_atm_rel_cas(st, NOT_READY, READY)) { /* swap was successful -- the closure will run after the next notify_on call. */ return; } /* swap was unsuccessful due to an intervening set_ready call. Fall through to the WAITING code below */ state = gpr_atm_acq_load(st); default: /* waiting */ GPR_ASSERT(gpr_atm_no_barrier_load(st) != READY && gpr_atm_no_barrier_load(st) != NOT_READY); callbacks[(*ncallbacks)++] = (grpc_iomgr_closure *)state; gpr_atm_rel_store(st, NOT_READY); return; } } static void set_ready(grpc_fd *fd, gpr_atm *st, int allow_synchronous_callback) { /* only one set_ready can be active at once (but there may be a racing notify_on) */ int success; grpc_iomgr_closure *closure; size_t ncb = 0; gpr_mu_lock(&fd->set_state_mu); set_ready_locked(st, &closure, &ncb); gpr_mu_unlock(&fd->set_state_mu); success = !gpr_atm_acq_load(&fd->shutdown); GPR_ASSERT(ncb <= 1); if (ncb > 0) { process_callbacks(closure, ncb, success, allow_synchronous_callback); } } void grpc_fd_shutdown(grpc_fd *fd) { size_t ncb = 0; gpr_mu_lock(&fd->set_state_mu); GPR_ASSERT(!gpr_atm_no_barrier_load(&fd->shutdown)); gpr_atm_rel_store(&fd->shutdown, 1); set_ready_locked(&fd->readst, &fd->shutdown_closures[0], &ncb); set_ready_locked(&fd->writest, &fd->shutdown_closures[0], &ncb); gpr_mu_unlock(&fd->set_state_mu); GPR_ASSERT(ncb <= 2); process_callbacks(fd->shutdown_closures[0], ncb, 0 /* GPR_FALSE */, 0 /* GPR_FALSE */); } void grpc_fd_notify_on_read(grpc_fd *fd, grpc_iomgr_closure *closure) { notify_on(fd, &fd->readst, closure, 0); } void grpc_fd_notify_on_write(grpc_fd *fd, grpc_iomgr_closure *closure) { notify_on(fd, &fd->writest, closure, 0); } gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, gpr_uint32 read_mask, gpr_uint32 write_mask, grpc_fd_watcher *watcher) { gpr_uint32 mask = 0; /* keep track of pollers that have requested our events, in case they change */ GRPC_FD_REF(fd, "poll"); gpr_mu_lock(&fd->watcher_mu); /* if we are shutdown, then don't add to the watcher set */ if (gpr_atm_no_barrier_load(&fd->shutdown)) { watcher->fd = NULL; watcher->pollset = NULL; gpr_mu_unlock(&fd->watcher_mu); GRPC_FD_UNREF(fd, "poll"); return 0; } /* if there is nobody polling for read, but we need to, then start doing so */ if (read_mask && !fd->read_watcher && (gpr_uintptr)gpr_atm_acq_load(&fd->readst) > READY) { fd->read_watcher = watcher; mask |= read_mask; } /* if there is nobody polling for write, but we need to, then start doing so */ if (write_mask && !fd->write_watcher && (gpr_uintptr)gpr_atm_acq_load(&fd->writest) > READY) { fd->write_watcher = watcher; mask |= write_mask; } /* if not polling, remember this watcher in case we need someone to later */ if (mask == 0) { watcher->next = &fd->inactive_watcher_root; watcher->prev = watcher->next->prev; watcher->next->prev = watcher->prev->next = watcher; } watcher->pollset = pollset; watcher->fd = fd; gpr_mu_unlock(&fd->watcher_mu); return mask; } void grpc_fd_end_poll(grpc_fd_watcher *watcher, int got_read, int got_write) { int was_polling = 0; int kick = 0; grpc_fd *fd = watcher->fd; if (fd == NULL) { return; } gpr_mu_lock(&fd->watcher_mu); if (watcher == fd->read_watcher) { /* remove read watcher, kick if we still need a read */ was_polling = 1; kick = kick || !got_read; fd->read_watcher = NULL; } if (watcher == fd->write_watcher) { /* remove write watcher, kick if we still need a write */ was_polling = 1; kick = kick || !got_write; fd->write_watcher = NULL; } if (!was_polling) { /* remove from inactive list */ watcher->next->prev = watcher->prev; watcher->prev->next = watcher->next; } if (kick) { maybe_wake_one_watcher_locked(fd); } if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) { fd->closed = 1; close(fd->fd); if (fd->on_done_closure != NULL) { grpc_iomgr_add_callback(fd->on_done_closure); } } gpr_mu_unlock(&fd->watcher_mu); GRPC_FD_UNREF(fd, "poll"); } void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback) { set_ready(fd, &fd->readst, allow_synchronous_callback); } void grpc_fd_become_writable(grpc_fd *fd, int allow_synchronous_callback) { set_ready(fd, &fd->writest, allow_synchronous_callback); } #endif grpc-0.11.1/src/core/iomgr/iomgr_posix.h0000644000175000017500000000346012600663151020266 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H #include "src/core/iomgr/iomgr_internal.h" void grpc_pollset_global_init(void); void grpc_pollset_global_shutdown(void); #endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H */ grpc-0.11.1/src/core/iomgr/sockaddr_utils.h0000644000175000017500000000754212600663151020746 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H #define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H #include "src/core/iomgr/sockaddr.h" /* Returns true if addr is an IPv4-mapped IPv6 address within the ::ffff:0.0.0.0/96 range, or false otherwise. If addr4_out is non-NULL, the inner IPv4 address will be copied here when returning true. */ int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, struct sockaddr_in *addr4_out); /* If addr is an AF_INET address, writes the corresponding ::ffff:0.0.0.0/96 address to addr6_out and returns true. Otherwise returns false. */ int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, struct sockaddr_in6 *addr6_out); /* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to *port_out (if not NULL) and returns true, otherwise returns false. */ int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out); /* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */ void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, struct sockaddr_in6 *wild6_out); /* Writes 0.0.0.0:port. */ void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out); /* Writes [::]:port. */ void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out); /* Return the IP port number of a sockaddr */ int grpc_sockaddr_get_port(const struct sockaddr *addr); /* Set IP port number of a sockaddr */ int grpc_sockaddr_set_port(const struct sockaddr *addr, int port); /* Converts a sockaddr into a newly-allocated human-readable string. Currently, only the AF_INET and AF_INET6 families are recognized. If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are displayed as plain IPv4. Usage is similar to gpr_asprintf: returns the number of bytes written (excluding the final '\0'), and *out points to a string which must later be destroyed using gpr_free(). In the unlikely event of an error, returns -1 and sets *out to NULL. The existing value of errno is always preserved. */ int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, int normalize); char *grpc_sockaddr_to_uri(const struct sockaddr *addr); #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */ grpc-0.11.1/src/core/iomgr/pollset_set_windows.c0000644000175000017500000000405212600663151022027 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include "src/core/iomgr/pollset_set.h" void grpc_pollset_set_init(grpc_pollset_set *pollset_set) {} void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {} void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set, grpc_pollset *pollset) {} void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set, grpc_pollset *pollset) {} #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/tcp_server_posix.c0000644000175000017500000003501312600663151021317 0ustar apollockapollock/* * * 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. * */ /* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/tcp_server.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "src/core/iomgr/pollset_posix.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_utils_posix.h" #include "src/core/iomgr/tcp_posix.h" #include "src/core/support/string.h" #include #include #include #include #include #define INIT_PORT_CAP 2 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 static gpr_once s_init_max_accept_queue_size; static int s_max_accept_queue_size; /* one listening port */ typedef struct { int fd; grpc_fd *emfd; grpc_tcp_server *server; union { gpr_uint8 untyped[GRPC_MAX_SOCKADDR_SIZE]; struct sockaddr sockaddr; struct sockaddr_un un; } addr; int addr_len; grpc_iomgr_closure read_closure; grpc_iomgr_closure destroyed_closure; } server_port; static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) { struct stat st; if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { unlink(un->sun_path); } } /* the overall server */ struct grpc_tcp_server { grpc_tcp_server_cb cb; void *cb_arg; gpr_mu mu; /* active port count: how many ports are actually still listening */ size_t active_ports; /* destroyed port count: how many ports are completely destroyed */ size_t destroyed_ports; /* is this server shutting down? (boolean) */ int shutdown; /* all listening ports */ server_port *ports; size_t nports; size_t port_capacity; /* shutdown callback */ void (*shutdown_complete)(void *); void *shutdown_complete_arg; /* all pollsets interested in new connections */ grpc_pollset **pollsets; /* number of pollsets in the pollsets array */ size_t pollset_count; }; grpc_tcp_server *grpc_tcp_server_create(void) { grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); gpr_mu_init(&s->mu); s->active_ports = 0; s->destroyed_ports = 0; s->shutdown = 0; s->cb = NULL; s->cb_arg = NULL; s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); s->nports = 0; s->port_capacity = INIT_PORT_CAP; return s; } static void finish_shutdown(grpc_tcp_server *s) { s->shutdown_complete(s->shutdown_complete_arg); s->shutdown_complete = NULL; gpr_mu_destroy(&s->mu); gpr_free(s->ports); gpr_free(s); } static void destroyed_port(void *server, int success) { grpc_tcp_server *s = server; gpr_mu_lock(&s->mu); s->destroyed_ports++; if (s->destroyed_ports == s->nports) { gpr_mu_unlock(&s->mu); finish_shutdown(s); } else { GPR_ASSERT(s->destroyed_ports < s->nports); gpr_mu_unlock(&s->mu); } } static void dont_care_about_shutdown_completion(void *ignored) {} /* called when all listening endpoints have been shutdown, so no further events will be received on them - at this point it's safe to destroy things */ static void deactivated_all_ports(grpc_tcp_server *s) { size_t i; /* delete ALL the things */ gpr_mu_lock(&s->mu); if (!s->shutdown) { gpr_mu_unlock(&s->mu); return; } if (s->nports) { for (i = 0; i < s->nports; i++) { server_port *sp = &s->ports[i]; if (sp->addr.sockaddr.sa_family == AF_UNIX) { unlink_if_unix_domain_socket(&sp->addr.un); } sp->destroyed_closure.cb = destroyed_port; sp->destroyed_closure.cb_arg = s; grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, "tcp_listener_shutdown"); } gpr_mu_unlock(&s->mu); } else { gpr_mu_unlock(&s->mu); finish_shutdown(s); } } void grpc_tcp_server_destroy( grpc_tcp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg), void *shutdown_complete_arg) { size_t i; gpr_mu_lock(&s->mu); GPR_ASSERT(!s->shutdown); s->shutdown = 1; s->shutdown_complete = shutdown_complete ? shutdown_complete : dont_care_about_shutdown_completion; s->shutdown_complete_arg = shutdown_complete_arg; /* shutdown all fd's */ if (s->active_ports) { for (i = 0; i < s->nports; i++) { grpc_fd_shutdown(s->ports[i].emfd); } gpr_mu_unlock(&s->mu); } else { gpr_mu_unlock(&s->mu); deactivated_all_ports(s); } } /* get max listen queue size on linux */ static void init_max_accept_queue_size(void) { int n = SOMAXCONN; char buf[64]; FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r"); if (fp == NULL) { /* 2.4 kernel. */ s_max_accept_queue_size = SOMAXCONN; return; } if (fgets(buf, sizeof buf, fp)) { char *end; long i = strtol(buf, &end, 10); if (i > 0 && i <= INT_MAX && end && *end == 0) { n = i; } } fclose(fp); s_max_accept_queue_size = n; if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) { gpr_log(GPR_INFO, "Suspiciously small accept queue (%d) will probably lead to " "connection drops", s_max_accept_queue_size); } } static int get_max_accept_queue_size(void) { gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size); return s_max_accept_queue_size; } /* Prepare a recently-created socket for listening. */ static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) { struct sockaddr_storage sockname_temp; socklen_t sockname_len; if (fd < 0) { goto error; } if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || (addr->sa_family != AF_UNIX && (!grpc_set_socket_low_latency(fd, 1) || !grpc_set_socket_reuse_addr(fd, 1))) || !grpc_set_socket_no_sigpipe_if_possible(fd)) { gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, strerror(errno)); goto error; } if (bind(fd, addr, addr_len) < 0) { char *addr_str; grpc_sockaddr_to_string(&addr_str, addr, 0); gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); gpr_free(addr_str); goto error; } if (listen(fd, get_max_accept_queue_size()) < 0) { gpr_log(GPR_ERROR, "listen: %s", strerror(errno)); goto error; } sockname_len = sizeof(sockname_temp); if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { goto error; } return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); error: if (fd >= 0) { close(fd); } return -1; } /* event manager callback when reads are ready */ static void on_read(void *arg, int success) { server_port *sp = arg; grpc_fd *fdobj; size_t i; if (!success) { goto error; } /* loop until accept4 returns EAGAIN, and then re-arm notification */ for (;;) { struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); char *addr_str; char *name; /* Note: If we ever decide to return this address to the user, remember to strip off the ::ffff:0.0.0.0/96 prefix first. */ int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1); if (fd < 0) { switch (errno) { case EINTR: continue; case EAGAIN: grpc_fd_notify_on_read(sp->emfd, &sp->read_closure); return; default: gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); goto error; } } grpc_set_socket_no_sigpipe_if_possible(fd); addr_str = grpc_sockaddr_to_uri((struct sockaddr *)&addr); gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); fdobj = grpc_fd_create(fd, name); /* TODO(ctiller): revise this when we have server-side sharding of channels -- we certainly should not be automatically adding every incoming channel to every pollset owned by the server */ for (i = 0; i < sp->server->pollset_count; i++) { grpc_pollset_add_fd(sp->server->pollsets[i], fdobj); } sp->server->cb( sp->server->cb_arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str)); gpr_free(name); gpr_free(addr_str); } abort(); error: gpr_mu_lock(&sp->server->mu); if (0 == --sp->server->active_ports) { gpr_mu_unlock(&sp->server->mu); deactivated_all_ports(sp->server); } else { gpr_mu_unlock(&sp->server->mu); } } static int add_socket_to_server(grpc_tcp_server *s, int fd, const struct sockaddr *addr, int addr_len) { server_port *sp; int port; char *addr_str; char *name; port = prepare_socket(fd, addr, addr_len); if (port >= 0) { grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->cb && "must add ports before starting server"); /* append it to the list under a lock */ if (s->nports == s->port_capacity) { s->port_capacity *= 2; s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); } sp = &s->ports[s->nports++]; sp->server = s; sp->fd = fd; sp->emfd = grpc_fd_create(fd, name); memcpy(sp->addr.untyped, addr, addr_len); sp->addr_len = addr_len; GPR_ASSERT(sp->emfd); gpr_mu_unlock(&s->mu); gpr_free(addr_str); gpr_free(name); } return port; } int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, int addr_len) { int allocated_port1 = -1; int allocated_port2 = -1; unsigned i; int fd; grpc_dualstack_mode dsmode; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in wild4; struct sockaddr_in6 wild6; struct sockaddr_in addr4_copy; struct sockaddr *allocated_addr = NULL; struct sockaddr_storage sockname_temp; socklen_t sockname_len; int port; if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { unlink_if_unix_domain_socket(addr); } /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { for (i = 0; i < s->nports; i++) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); allocated_port1 = add_socket_to_server(s, fd, addr, addr_len); if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ if (port == 0 && allocated_port1 > 0) { grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1); } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); } fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } allocated_port2 = add_socket_to_server(s, fd, addr, addr_len); done: gpr_free(allocated_addr); return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; } int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index) { return (index < s->nports) ? s->ports[index].fd : -1; } void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollsets, size_t pollset_count, grpc_tcp_server_cb cb, void *cb_arg) { size_t i, j; GPR_ASSERT(cb); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->cb); GPR_ASSERT(s->active_ports == 0); s->cb = cb; s->cb_arg = cb_arg; s->pollsets = pollsets; s->pollset_count = pollset_count; for (i = 0; i < s->nports; i++) { for (j = 0; j < pollset_count; j++) { grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd); } s->ports[i].read_closure.cb = on_read; s->ports[i].read_closure.cb_arg = &s->ports[i]; grpc_fd_notify_on_read(s->ports[i].emfd, &s->ports[i].read_closure); s->active_ports++; } gpr_mu_unlock(&s->mu); } #endif grpc-0.11.1/src/core/iomgr/udp_server.c0000644000175000017500000003126612600663151020105 0ustar apollockapollock/* * * 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. * */ /* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/udp_server.h" #include #include #include #include #include #include #include #include #include #include #include #include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/pollset_posix.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_utils_posix.h" #include "src/core/support/string.h" #include #include #include #include #include #define INIT_PORT_CAP 2 /* one listening port */ typedef struct { int fd; grpc_fd *emfd; grpc_udp_server *server; union { gpr_uint8 untyped[GRPC_MAX_SOCKADDR_SIZE]; struct sockaddr sockaddr; struct sockaddr_un un; } addr; int addr_len; grpc_iomgr_closure read_closure; grpc_iomgr_closure destroyed_closure; grpc_udp_server_read_cb read_cb; } server_port; static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) { struct stat st; if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { unlink(un->sun_path); } } /* the overall server */ struct grpc_udp_server { grpc_udp_server_cb cb; void *cb_arg; gpr_mu mu; gpr_cv cv; /* active port count: how many ports are actually still listening */ size_t active_ports; /* destroyed port count: how many ports are completely destroyed */ size_t destroyed_ports; /* is this server shutting down? (boolean) */ int shutdown; /* all listening ports */ server_port *ports; size_t nports; size_t port_capacity; /* shutdown callback */ void (*shutdown_complete)(void *); void *shutdown_complete_arg; /* all pollsets interested in new connections */ grpc_pollset **pollsets; /* number of pollsets in the pollsets array */ size_t pollset_count; }; grpc_udp_server *grpc_udp_server_create(void) { grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server)); gpr_mu_init(&s->mu); gpr_cv_init(&s->cv); s->active_ports = 0; s->destroyed_ports = 0; s->shutdown = 0; s->cb = NULL; s->cb_arg = NULL; s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); s->nports = 0; s->port_capacity = INIT_PORT_CAP; return s; } static void finish_shutdown(grpc_udp_server *s) { s->shutdown_complete(s->shutdown_complete_arg); gpr_mu_destroy(&s->mu); gpr_cv_destroy(&s->cv); gpr_free(s->ports); gpr_free(s); } static void destroyed_port(void *server, int success) { grpc_udp_server *s = server; gpr_mu_lock(&s->mu); s->destroyed_ports++; if (s->destroyed_ports == s->nports) { gpr_mu_unlock(&s->mu); finish_shutdown(s); } else { gpr_mu_unlock(&s->mu); } } static void dont_care_about_shutdown_completion(void *ignored) {} /* called when all listening endpoints have been shutdown, so no further events will be received on them - at this point it's safe to destroy things */ static void deactivated_all_ports(grpc_udp_server *s) { size_t i; /* delete ALL the things */ gpr_mu_lock(&s->mu); if (!s->shutdown) { gpr_mu_unlock(&s->mu); return; } if (s->nports) { for (i = 0; i < s->nports; i++) { server_port *sp = &s->ports[i]; if (sp->addr.sockaddr.sa_family == AF_UNIX) { unlink_if_unix_domain_socket(&sp->addr.un); } sp->destroyed_closure.cb = destroyed_port; sp->destroyed_closure.cb_arg = s; grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, "udp_listener_shutdown"); } gpr_mu_unlock(&s->mu); } else { gpr_mu_unlock(&s->mu); finish_shutdown(s); } } void grpc_udp_server_destroy( grpc_udp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg), void *shutdown_complete_arg) { size_t i; gpr_mu_lock(&s->mu); GPR_ASSERT(!s->shutdown); s->shutdown = 1; s->shutdown_complete = shutdown_complete ? shutdown_complete : dont_care_about_shutdown_completion; s->shutdown_complete_arg = shutdown_complete_arg; /* shutdown all fd's */ if (s->active_ports) { for (i = 0; i < s->nports; i++) { grpc_fd_shutdown(s->ports[i].emfd); } gpr_mu_unlock(&s->mu); } else { gpr_mu_unlock(&s->mu); deactivated_all_ports(s); } } /* Prepare a recently-created socket for listening. */ static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) { struct sockaddr_storage sockname_temp; socklen_t sockname_len; int get_local_ip; int rc; if (fd < 0) { goto error; } get_local_ip = 1; rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip, sizeof(get_local_ip)); if (rc == 0 && addr->sa_family == AF_INET6) { #if !TARGET_OS_IPHONE rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip, sizeof(get_local_ip)); #endif } if (bind(fd, addr, addr_len) < 0) { char *addr_str; grpc_sockaddr_to_string(&addr_str, addr, 0); gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); gpr_free(addr_str); goto error; } sockname_len = sizeof(sockname_temp); if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { goto error; } return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); error: if (fd >= 0) { close(fd); } return -1; } /* event manager callback when reads are ready */ static void on_read(void *arg, int success) { server_port *sp = arg; if (success == 0) { gpr_mu_lock(&sp->server->mu); if (0 == --sp->server->active_ports) { gpr_mu_unlock(&sp->server->mu); deactivated_all_ports(sp->server); } else { gpr_mu_unlock(&sp->server->mu); } return; } /* Tell the registered callback that data is available to read. */ GPR_ASSERT(sp->read_cb); sp->read_cb(sp->fd, sp->server->cb, sp->server->cb_arg); /* Re-arm the notification event so we get another chance to read. */ grpc_fd_notify_on_read(sp->emfd, &sp->read_closure); } static int add_socket_to_server(grpc_udp_server *s, int fd, const struct sockaddr *addr, int addr_len, grpc_udp_server_read_cb read_cb) { server_port *sp; int port; char *addr_str; char *name; port = prepare_socket(fd, addr, addr_len); if (port >= 0) { grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); gpr_asprintf(&name, "udp-server-listener:%s", addr_str); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->cb && "must add ports before starting server"); /* append it to the list under a lock */ if (s->nports == s->port_capacity) { s->port_capacity *= 2; s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); } sp = &s->ports[s->nports++]; sp->server = s; sp->fd = fd; sp->emfd = grpc_fd_create(fd, name); memcpy(sp->addr.untyped, addr, addr_len); sp->addr_len = addr_len; sp->read_cb = read_cb; GPR_ASSERT(sp->emfd); gpr_mu_unlock(&s->mu); } return port; } int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, int addr_len, grpc_udp_server_read_cb read_cb) { int allocated_port1 = -1; int allocated_port2 = -1; unsigned i; int fd; grpc_dualstack_mode dsmode; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in wild4; struct sockaddr_in6 wild6; struct sockaddr_in addr4_copy; struct sockaddr *allocated_addr = NULL; struct sockaddr_storage sockname_temp; socklen_t sockname_len; int port; if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { unlink_if_unix_domain_socket(addr); } /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { for (i = 0; i < s->nports; i++) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcards(port, &wild4, &wild6); /* Try listening on IPv6 first. */ 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); if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ if (port == 0 && allocated_port1 > 0) { grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1); } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); } fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } if (dsmode == GRPC_DSMODE_IPV4 && grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb); done: gpr_free(allocated_addr); return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; } int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index) { return (index < s->nports) ? s->ports[index].fd : -1; } void grpc_udp_server_start(grpc_udp_server *s, grpc_pollset **pollsets, size_t pollset_count, grpc_udp_server_cb new_transport_cb, void *cb_arg) { size_t i, j; GPR_ASSERT(new_transport_cb); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->cb); GPR_ASSERT(s->active_ports == 0); s->cb = new_transport_cb; s->cb_arg = cb_arg; s->pollsets = pollsets; for (i = 0; i < s->nports; i++) { for (j = 0; j < pollset_count; j++) { grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd); } s->ports[i].read_closure.cb = on_read; s->ports[i].read_closure.cb_arg = &s->ports[i]; grpc_fd_notify_on_read(s->ports[i].emfd, &s->ports[i].read_closure); s->active_ports++; } gpr_mu_unlock(&s->mu); } /* TODO(rjshade): Add a test for this method. */ void grpc_udp_server_write(server_port *sp, const char *buffer, size_t buf_len, const struct sockaddr *peer_address) { int rc; rc = sendto(sp->fd, buffer, buf_len, 0, peer_address, sizeof(peer_address)); if (rc < 0) { gpr_log(GPR_ERROR, "Unable to send data: %s", strerror(errno)); } } #endif grpc-0.11.1/src/core/iomgr/pollset_set_posix.h0000644000175000017500000000417012600663151021505 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H #include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/pollset_posix.h" typedef struct grpc_pollset_set { gpr_mu mu; size_t pollset_count; size_t pollset_capacity; grpc_pollset **pollsets; size_t fd_count; size_t fd_capacity; grpc_fd **fds; } grpc_pollset_set; void grpc_pollset_set_add_fd(grpc_pollset_set *pollset_set, grpc_fd *fd); void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd); #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */ grpc-0.11.1/src/core/iomgr/socket_utils_common_posix.c0000644000175000017500000001417312600663151023227 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/socket_utils_posix.h" #include #include #include #include #include #include #include #include #include #include #include #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/support/string.h" #include #include #include #include /* set a socket to non blocking mode */ int grpc_set_socket_nonblocking(int fd, int non_blocking) { int oldflags = fcntl(fd, F_GETFL, 0); if (oldflags < 0) { return 0; } if (non_blocking) { oldflags |= O_NONBLOCK; } else { oldflags &= ~O_NONBLOCK; } if (fcntl(fd, F_SETFL, oldflags) != 0) { return 0; } return 1; } int grpc_set_socket_no_sigpipe_if_possible(int fd) { #ifdef GPR_HAVE_SO_NOSIGPIPE int val = 1; int newval; socklen_t intlen = sizeof(newval); return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) && 0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) && (newval != 0) == val; #else return 1; #endif } /* set a socket to close on exec */ int grpc_set_socket_cloexec(int fd, int close_on_exec) { int oldflags = fcntl(fd, F_GETFD, 0); if (oldflags < 0) { return 0; } if (close_on_exec) { oldflags |= FD_CLOEXEC; } else { oldflags &= ~FD_CLOEXEC; } if (fcntl(fd, F_SETFD, oldflags) != 0) { return 0; } return 1; } /* set a socket to reuse old addresses */ int grpc_set_socket_reuse_addr(int fd, int reuse) { int val = (reuse != 0); int newval; socklen_t intlen = sizeof(newval); return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) && 0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) && (newval != 0) == val; } /* disable nagle */ int grpc_set_socket_low_latency(int fd, int low_latency) { int val = (low_latency != 0); int newval; socklen_t intlen = sizeof(newval); return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) && 0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) && (newval != 0) == val; } static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT; static int g_ipv6_loopback_available; static void probe_ipv6_once(void) { int fd = socket(AF_INET6, SOCK_STREAM, 0); g_ipv6_loopback_available = 0; if (fd < 0) { gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed."); } else { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) { g_ipv6_loopback_available = 1; } else { gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because ::1 is not available."); } close(fd); } } int grpc_ipv6_loopback_available(void) { gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once); return g_ipv6_loopback_available; } /* This should be 0 in production, but it may be enabled for testing or debugging purposes, to simulate an environment where IPv6 sockets can't also speak IPv4. */ int grpc_forbid_dualstack_sockets_for_testing = 0; static int set_socket_dualstack(int fd) { if (!grpc_forbid_dualstack_sockets_for_testing) { const int off = 0; return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); } else { /* Force an IPv6-only socket, for testing purposes. */ const int on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); return 0; } } int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, int protocol, grpc_dualstack_mode *dsmode) { int family = addr->sa_family; if (family == AF_INET6) { int fd; if (grpc_ipv6_loopback_available()) { fd = socket(family, type, protocol); } else { fd = -1; errno = EAFNOSUPPORT; } /* Check if we've got a valid dualstack socket. */ if (fd >= 0 && set_socket_dualstack(fd)) { *dsmode = GRPC_DSMODE_DUALSTACK; return fd; } /* If this isn't an IPv4 address, then return whatever we've got. */ if (!grpc_sockaddr_is_v4mapped(addr, NULL)) { *dsmode = GRPC_DSMODE_IPV6; return fd; } /* Fall back to AF_INET. */ if (fd >= 0) { close(fd); } family = AF_INET; } *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE; return socket(family, type, protocol); } #endif grpc-0.11.1/src/core/iomgr/pollset.h0000644000175000017500000000740312600663151017412 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_H #include #include #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) /* A grpc_pollset is a set of file descriptors that a higher level item is interested in. For example: - a server will typically keep a pollset containing all connected channels, so that it can find new calls to service - a completion queue might keep a pollset with an entry for each transport that is servicing a call that it's tracking */ #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/pollset_posix.h" #endif #ifdef GPR_WIN32 #include "src/core/iomgr/pollset_windows.h" #endif void grpc_pollset_init(grpc_pollset *pollset); void grpc_pollset_shutdown(grpc_pollset *pollset, void (*shutdown_done)(void *arg), void *shutdown_done_arg); void grpc_pollset_destroy(grpc_pollset *pollset); /* Do some work on a pollset. May involve invoking asynchronous callbacks, or actually polling file descriptors. Requires GRPC_POLLSET_MU(pollset) locked. May unlock GRPC_POLLSET_MU(pollset) during its execution. worker is a (platform-specific) handle that can be used to wake up from grpc_pollset_work before any events are received and before the timeout has expired. It is both initialized and destroyed by grpc_pollset_work. Initialization of worker is guaranteed to occur BEFORE the GRPC_POLLSET_MU(pollset) is released for the first time by grpc_pollset_work, and it is guaranteed that GRPC_POLLSET_MU(pollset) will not be released by grpc_pollset_work AFTER worker has been destroyed. Tries not to block past deadline. */ void grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec now, gpr_timespec deadline); /* Break one polling thread out of polling work for this pollset. If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers. Otherwise, if specific_worker is non-NULL, then kick that worker. */ void grpc_pollset_kick(grpc_pollset *pollset, grpc_pollset_worker *specific_worker); #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */ grpc-0.11.1/src/core/iomgr/pollset_multipoller_with_poll_posix.c0000644000175000017500000001673712600663151025352 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/pollset_posix.h" #include #include #include #include #include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/iomgr_internal.h" #include #include #include typedef struct { /* all polled fds */ size_t fd_count; size_t fd_capacity; grpc_fd **fds; /* fds that have been removed from the pollset explicitly */ size_t del_count; size_t del_capacity; grpc_fd **dels; } pollset_hdr; static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd, int and_unlock_pollset) { size_t i; pollset_hdr *h = pollset->data.ptr; /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */ for (i = 0; i < h->fd_count; i++) { if (h->fds[i] == fd) goto exit; } if (h->fd_count == h->fd_capacity) { h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2); h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity); } h->fds[h->fd_count++] = fd; GRPC_FD_REF(fd, "multipoller"); exit: if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); } } static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd, int and_unlock_pollset) { /* will get removed next poll cycle */ pollset_hdr *h = pollset->data.ptr; if (h->del_count == h->del_capacity) { h->del_capacity = GPR_MAX(h->del_capacity + 8, h->del_count * 3 / 2); h->dels = gpr_realloc(h->dels, sizeof(grpc_fd *) * h->del_capacity); } h->dels[h->del_count++] = fd; GRPC_FD_REF(fd, "multipoller_del"); if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); } } static void multipoll_with_poll_pollset_maybe_work( grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline, gpr_timespec now, int allow_synchronous_callback) { int timeout; int r; size_t i, j, pfd_count, fd_count; pollset_hdr *h; /* TODO(ctiller): inline some elements to avoid an allocation */ grpc_fd_watcher *watchers; struct pollfd *pfds; h = pollset->data.ptr; timeout = grpc_poll_deadline_to_millis_timeout(deadline, now); /* TODO(ctiller): perform just one malloc here if we exceed the inline case */ pfds = gpr_malloc(sizeof(*pfds) * (h->fd_count + 1)); watchers = gpr_malloc(sizeof(*watchers) * (h->fd_count + 1)); fd_count = 0; pfd_count = 1; pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd); pfds[0].events = POLLIN; pfds[0].revents = POLLOUT; for (i = 0; i < h->fd_count; i++) { int remove = grpc_fd_is_orphaned(h->fds[i]); for (j = 0; !remove && j < h->del_count; j++) { if (h->fds[i] == h->dels[j]) remove = 1; } if (remove) { GRPC_FD_UNREF(h->fds[i], "multipoller"); } else { h->fds[fd_count++] = h->fds[i]; watchers[pfd_count].fd = h->fds[i]; pfds[pfd_count].fd = h->fds[i]->fd; pfds[pfd_count].revents = 0; pfd_count++; } } for (j = 0; j < h->del_count; j++) { GRPC_FD_UNREF(h->dels[j], "multipoller_del"); } h->del_count = 0; h->fd_count = fd_count; gpr_mu_unlock(&pollset->mu); for (i = 1; i < pfd_count; i++) { pfds[i].events = grpc_fd_begin_poll(watchers[i].fd, pollset, POLLIN, POLLOUT, &watchers[i]); } r = grpc_poll_function(pfds, pfd_count, timeout); for (i = 1; i < pfd_count; i++) { grpc_fd_end_poll(&watchers[i], pfds[i].revents & POLLIN, pfds[i].revents & POLLOUT); } if (r < 0) { if (errno != EINTR) { gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); } } else if (r == 0) { /* do nothing */ } else { if (pfds[0].revents & POLLIN) { grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd); } for (i = 1; i < pfd_count; i++) { if (watchers[i].fd == NULL) { continue; } if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) { grpc_fd_become_readable(watchers[i].fd, allow_synchronous_callback); } if (pfds[i].revents & (POLLOUT | POLLHUP | POLLERR)) { grpc_fd_become_writable(watchers[i].fd, allow_synchronous_callback); } } } gpr_free(pfds); gpr_free(watchers); gpr_mu_lock(&pollset->mu); } static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) { size_t i; pollset_hdr *h = pollset->data.ptr; for (i = 0; i < h->fd_count; i++) { GRPC_FD_UNREF(h->fds[i], "multipoller"); } for (i = 0; i < h->del_count; i++) { GRPC_FD_UNREF(h->dels[i], "multipoller_del"); } h->fd_count = 0; h->del_count = 0; } static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) { pollset_hdr *h = pollset->data.ptr; multipoll_with_poll_pollset_finish_shutdown(pollset); gpr_free(h->fds); gpr_free(h->dels); gpr_free(h); } static const grpc_pollset_vtable multipoll_with_poll_pollset = { multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd, multipoll_with_poll_pollset_maybe_work, multipoll_with_poll_pollset_finish_shutdown, multipoll_with_poll_pollset_destroy}; void grpc_poll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds, size_t nfds) { size_t i; pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); pollset->vtable = &multipoll_with_poll_pollset; pollset->data.ptr = h; h->fd_count = nfds; h->fd_capacity = nfds; h->fds = gpr_malloc(nfds * sizeof(grpc_fd *)); h->del_count = 0; h->del_capacity = 0; h->dels = NULL; for (i = 0; i < nfds; i++) { h->fds[i] = fds[i]; GRPC_FD_REF(fds[i], "multipoller"); } } #endif /* GPR_POSIX_SOCKET */ #ifdef GPR_POSIX_MULTIPOLL_WITH_POLL grpc_platform_become_multipoller_type grpc_platform_become_multipoller = grpc_poll_become_multipoller; #endif grpc-0.11.1/src/core/iomgr/iomgr_windows.c0000644000175000017500000000463112600663151020612 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include "src/core/iomgr/sockaddr_win32.h" #include #include "src/core/iomgr/socket_windows.h" #include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/iomgr.h" /* Windows' io manager is going to be fully designed using IO completion ports. All of what we're doing here is basically make sure that Windows sockets are initialized in and out. */ static void winsock_init(void) { WSADATA wsaData; int status = WSAStartup(MAKEWORD(2, 0), &wsaData); GPR_ASSERT(status == 0); } static void winsock_shutdown(void) { int status = WSACleanup(); GPR_ASSERT(status == 0); } void grpc_iomgr_platform_init(void) { winsock_init(); grpc_iocp_init(); } void grpc_iomgr_platform_shutdown(void) { grpc_iocp_shutdown(); winsock_shutdown(); } #endif /* GRPC_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/time_averaged_stats.h0000644000175000017500000001061612600663151021742 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H #define GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H /* This tracks a time-decaying weighted average. It works by collecting batches of samples and then mixing their average into a time-decaying weighted mean. It is designed for batch operations where we do many adds before updating the average. */ typedef struct { /* The initial average value. This is the reported average until the first grpc_time_averaged_stats_update_average call. If a positive regress_weight is used, we also regress towards this value on each update. */ double init_avg; /* The sample weight of "init_avg" that is mixed in with each call to grpc_time_averaged_stats_update_average. If the calls to grpc_time_averaged_stats_add_sample stop, this will cause the average to regress back to the mean. This should be non-negative. Set it to 0 to disable the bias. A value of 1 has the effect of adding in 1 bonus sample with value init_avg to each sample period. */ double regress_weight; /* This determines the rate of decay of the time-averaging from one period to the next by scaling the aggregate_total_weight of samples from prior periods when combining with the latest period. It should be in the range [0,1]. A higher value adapts more slowly. With a value of 0.5, if the batches each have k samples, the samples_in_avg_ will grow to 2 k, so the weighting of the time average will eventually be 1/3 new batch and 2/3 old average. */ double persistence_factor; /* The total value of samples since the last UpdateAverage(). */ double batch_total_value; /* The number of samples since the last UpdateAverage(). */ double batch_num_samples; /* The time-decayed sum of batch_num_samples_ over previous batches. This is the "weight" of the old aggregate_weighted_avg_ when updating the average. */ double aggregate_total_weight; /* A time-decayed average of the (batch_total_value_ / batch_num_samples_), computed by decaying the samples_in_avg_ weight in the weighted average. */ double aggregate_weighted_avg; } grpc_time_averaged_stats; /* See the comments on the members above for an explanation of init_avg, regress_weight, and persistence_factor. */ void grpc_time_averaged_stats_init(grpc_time_averaged_stats *stats, double init_avg, double regress_weight, double persistence_factor); /* Add a sample to the current batch. */ void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats *stats, double value); /* Complete a batch and compute the new estimate of the average sample value. */ double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats *stats); #endif /* GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H */ grpc-0.11.1/src/core/iomgr/endpoint.h0000644000175000017500000001076612600663151017556 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H #define GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_set.h" #include #include #include /* An endpoint caps a streaming channel between two communicating processes. Examples may be: a tcp socket, , or some shared memory. */ typedef struct grpc_endpoint grpc_endpoint; typedef struct grpc_endpoint_vtable grpc_endpoint_vtable; typedef enum grpc_endpoint_op_status { GRPC_ENDPOINT_DONE, /* completed immediately, cb won't be called */ GRPC_ENDPOINT_PENDING, /* cb will be called when completed */ GRPC_ENDPOINT_ERROR /* write errored out, cb won't be called */ } grpc_endpoint_op_status; struct grpc_endpoint_vtable { grpc_endpoint_op_status (*read)(grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb); grpc_endpoint_op_status (*write)(grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb); void (*add_to_pollset)(grpc_endpoint *ep, grpc_pollset *pollset); void (*add_to_pollset_set)(grpc_endpoint *ep, grpc_pollset_set *pollset); void (*shutdown)(grpc_endpoint *ep); void (*destroy)(grpc_endpoint *ep); char *(*get_peer)(grpc_endpoint *ep); }; /* When data is available on the connection, calls the callback with slices. Callback success indicates that the endpoint can accept more reads, failure indicates the endpoint is closed. Valid slices may be placed into \a slices even on callback success == 0. */ grpc_endpoint_op_status grpc_endpoint_read( grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT; char *grpc_endpoint_get_peer(grpc_endpoint *ep); /* Write slices out to the socket. If the connection is ready for more data after the end of the call, it returns GRPC_ENDPOINT_DONE. Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the connection is ready for more data. \a slices may be mutated at will by the endpoint until cb is called. No guarantee is made to the content of slices after a write EXCEPT that it is a valid slice buffer. */ grpc_endpoint_op_status grpc_endpoint_write( grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT; /* Causes any pending read/write callbacks to run immediately with success==0 */ void grpc_endpoint_shutdown(grpc_endpoint *ep); void grpc_endpoint_destroy(grpc_endpoint *ep); /* Add an endpoint to a pollset, so that when the pollset is polled, events from this endpoint are considered */ void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset); void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set); struct grpc_endpoint { const grpc_endpoint_vtable *vtable; }; #endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H */ grpc-0.11.1/src/core/iomgr/tcp_server_windows.c0000644000175000017500000003703112600663151021651 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #define _GNU_SOURCE #include "src/core/iomgr/sockaddr_utils.h" #include #include #include #include #include #include #include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/pollset_windows.h" #include "src/core/iomgr/socket_windows.h" #include "src/core/iomgr/tcp_server.h" #include "src/core/iomgr/tcp_windows.h" #define INIT_PORT_CAP 2 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 /* one listening port */ typedef struct server_port { /* This seemingly magic number comes from AcceptEx's documentation. each address buffer needs to have at least 16 more bytes at their end. */ gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2]; /* This will hold the socket for the next accept. */ SOCKET new_socket; /* The listener winsocked. */ grpc_winsocket *socket; grpc_tcp_server *server; /* The cached AcceptEx for that port. */ LPFN_ACCEPTEX AcceptEx; int shutting_down; } server_port; /* the overall server */ struct grpc_tcp_server { grpc_tcp_server_cb cb; void *cb_arg; gpr_mu mu; /* active port count: how many ports are actually still listening */ int active_ports; /* all listening ports */ server_port *ports; size_t nports; size_t port_capacity; /* shutdown callback */ void(*shutdown_complete)(void *); void *shutdown_complete_arg; }; /* Public function. Allocates the proper data structures to hold a grpc_tcp_server. */ grpc_tcp_server *grpc_tcp_server_create(void) { grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); gpr_mu_init(&s->mu); s->active_ports = 0; s->cb = NULL; s->cb_arg = NULL; s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); s->nports = 0; s->port_capacity = INIT_PORT_CAP; s->shutdown_complete = NULL; return s; } static void dont_care_about_shutdown_completion(void *arg) {} static void finish_shutdown(grpc_tcp_server *s) { size_t i; s->shutdown_complete(s->shutdown_complete_arg); /* Now that the accepts have been aborted, we can destroy the sockets. The IOCP won't get notified on these, so we can flag them as already closed by the system. */ for (i = 0; i < s->nports; i++) { server_port *sp = &s->ports[i]; grpc_winsocket_destroy(sp->socket); } gpr_free(s->ports); gpr_free(s); } /* Public function. Stops and destroys a grpc_tcp_server. */ void grpc_tcp_server_destroy(grpc_tcp_server *s, void (*shutdown_complete)(void *shutdown_done_arg), void *shutdown_complete_arg) { size_t i; int immediately_done = 0; gpr_mu_lock(&s->mu); s->shutdown_complete = shutdown_complete ? shutdown_complete : dont_care_about_shutdown_completion; s->shutdown_complete_arg = shutdown_complete_arg; /* First, shutdown all fd's. This will queue abortion calls for all of the pending accepts due to the normal operation mechanism. */ if (s->active_ports == 0) { immediately_done = 1; } for (i = 0; i < s->nports; i++) { server_port *sp = &s->ports[i]; sp->shutting_down = 1; grpc_winsocket_shutdown(sp->socket); } gpr_mu_unlock(&s->mu); if (immediately_done) { finish_shutdown(s); } } /* Prepare (bind) a recently-created socket for listening. */ static int prepare_socket(SOCKET sock, const struct sockaddr *addr, int addr_len) { struct sockaddr_storage sockname_temp; socklen_t sockname_len; if (sock == INVALID_SOCKET) goto error; if (!grpc_tcp_prepare_socket(sock)) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message); gpr_free(utf8_message); goto error; } if (bind(sock, addr, addr_len) == SOCKET_ERROR) { char *addr_str; char *utf8_message = gpr_format_message(WSAGetLastError()); grpc_sockaddr_to_string(&addr_str, addr, 0); gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message); gpr_free(utf8_message); gpr_free(addr_str); goto error; } if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "listen: %s", utf8_message); gpr_free(utf8_message); goto error; } sockname_len = sizeof(sockname_temp); if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) == SOCKET_ERROR) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "getsockname: %s", utf8_message); gpr_free(utf8_message); goto error; } return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); error: if (sock != INVALID_SOCKET) closesocket(sock); return -1; } static void decrement_active_ports_and_notify(server_port *sp) { int notify = 0; sp->shutting_down = 0; gpr_mu_lock(&sp->server->mu); GPR_ASSERT(sp->server->active_ports > 0); if (0 == --sp->server->active_ports && sp->server->shutdown_complete != NULL) { notify = 1; } gpr_mu_unlock(&sp->server->mu); if (notify) { finish_shutdown(sp->server); } } /* start_accept will reference that for the IOCP notification request. */ static void on_accept(void *arg, int from_iocp); /* In order to do an async accept, we need to create a socket first which will be the one assigned to the new incoming connection. */ static void start_accept(server_port *port) { SOCKET sock = INVALID_SOCKET; char *message; char *utf8_message; BOOL success; DWORD addrlen = sizeof(struct sockaddr_in6) + 16; DWORD bytes_received = 0; sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { message = "Unable to create socket: %s"; goto failure; } if (!grpc_tcp_prepare_socket(sock)) { message = "Unable to prepare socket: %s"; goto failure; } /* Start the "accept" asynchronously. */ success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0, addrlen, addrlen, &bytes_received, &port->socket->read_info.overlapped); /* It is possible to get an accept immediately without delay. However, we will still get an IOCP notification for it. So let's just ignore it. */ if (!success) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { message = "AcceptEx failed: %s"; goto failure; } } /* We're ready to do the accept. Calling grpc_socket_notify_on_read may immediately process an accept that happened in the meantime. */ port->new_socket = sock; grpc_socket_notify_on_read(port->socket, on_accept, port); return; failure: if (port->shutting_down) { /* We are abandoning the listener port, take that into account to prevent occasional hangs on shutdown. The hang happens when sp->shutting_down change is not seen by on_accept and we proceed to trying new accept, but we fail there because the listening port has been closed in the meantime. */ decrement_active_ports_and_notify(port); return; } utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, message, utf8_message); gpr_free(utf8_message); if (sock != INVALID_SOCKET) closesocket(sock); } /* Event manager callback when reads are ready. */ static void on_accept(void *arg, int from_iocp) { server_port *sp = arg; SOCKET sock = sp->new_socket; grpc_winsocket_callback_info *info = &sp->socket->read_info; grpc_endpoint *ep = NULL; struct sockaddr_storage peer_name; char *peer_name_string; char *fd_name; int peer_name_len = sizeof(peer_name); DWORD transfered_bytes; DWORD flags; BOOL wsa_success; int err; /* The general mechanism for shutting down is to queue abortion calls. While this is necessary in the read/write case, it's useless for the accept case. We only need to adjust the pending callback count */ if (!from_iocp) { return; } /* The IOCP notified us of a completed operation. Let's grab the results, and act accordingly. */ transfered_bytes = 0; wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, &transfered_bytes, FALSE, &flags); if (!wsa_success) { if (sp->shutting_down) { /* During the shutdown case, we ARE expecting an error. So that's well, and we can wake up the shutdown thread. */ decrement_active_ports_and_notify(sp); return; } else { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message); gpr_free(utf8_message); closesocket(sock); } } else { if (!sp->shutting_down) { peer_name_string = NULL; err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&sp->socket->socket, sizeof(sp->socket->socket)); if (err) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); gpr_free(utf8_message); } err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len); if (!err) { peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name); } else { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message); gpr_free(utf8_message); } gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string); ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), peer_name_string); gpr_free(fd_name); gpr_free(peer_name_string); } } /* The only time we should call our callback, is where we successfully managed to accept a connection, and created an endpoint. */ if (ep) sp->server->cb(sp->server->cb_arg, ep); /* As we were notified from the IOCP of one and exactly one accept, the former socked we created has now either been destroy or assigned to the new connection. We need to create a new one for the next connection. */ start_accept(sp); } static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock, const struct sockaddr *addr, int addr_len) { server_port *sp; int port; int status; GUID guid = WSAID_ACCEPTEX; DWORD ioctl_num_bytes; LPFN_ACCEPTEX AcceptEx; if (sock == INVALID_SOCKET) return -1; /* We need to grab the AcceptEx pointer for that port, as it may be interface-dependent. We'll cache it to avoid doing that again. */ status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL); if (status != 0) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); gpr_free(utf8_message); closesocket(sock); return -1; } port = prepare_socket(sock, addr, addr_len); if (port >= 0) { gpr_mu_lock(&s->mu); GPR_ASSERT(!s->cb && "must add ports before starting server"); /* append it to the list under a lock */ if (s->nports == s->port_capacity) { s->port_capacity *= 2; s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); } sp = &s->ports[s->nports++]; sp->server = s; sp->socket = grpc_winsocket_create(sock, "listener"); sp->shutting_down = 0; sp->AcceptEx = AcceptEx; sp->new_socket = INVALID_SOCKET; GPR_ASSERT(sp->socket); gpr_mu_unlock(&s->mu); } return port; } int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, int addr_len) { int allocated_port = -1; unsigned i; SOCKET sock; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in6 wildcard; struct sockaddr *allocated_addr = NULL; struct sockaddr_storage sockname_temp; socklen_t sockname_len; int port; /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { for (i = 0; i < s->nports; i++) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(s->ports[i].socket->socket, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); grpc_sockaddr_set_port(allocated_addr, port); addr = allocated_addr; break; } } } } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); } /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcard6(port, &wildcard); addr = (struct sockaddr *)&wildcard; addr_len = sizeof(wildcard); } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message); gpr_free(utf8_message); } allocated_port = add_socket_to_server(s, sock, addr, addr_len); gpr_free(allocated_addr); return allocated_port; } SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) { return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET; } void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset, size_t pollset_count, grpc_tcp_server_cb cb, void *cb_arg) { size_t i; GPR_ASSERT(cb); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->cb); GPR_ASSERT(s->active_ports == 0); s->cb = cb; s->cb_arg = cb_arg; for (i = 0; i < s->nports; i++) { start_accept(s->ports + i); s->active_ports++; } gpr_mu_unlock(&s->mu); } #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/pollset_set_windows.h0000644000175000017500000000341612600663151022037 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H typedef struct grpc_pollset_set { void *unused; } grpc_pollset_set; #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */ grpc-0.11.1/src/core/iomgr/pollset_posix.c0000644000175000017500000004066512600663151020636 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/pollset_posix.h" #include #include #include #include #include "src/core/iomgr/alarm_internal.h" #include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/socket_utils_posix.h" #include "src/core/profiling/timers.h" #include #include #include #include #include GPR_TLS_DECL(g_current_thread_poller); GPR_TLS_DECL(g_current_thread_worker); grpc_poll_function_type grpc_poll_function = poll; static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->prev->next = worker->next; worker->next->prev = worker->prev; } int grpc_pollset_has_workers(grpc_pollset *p) { return p->root_worker.next != &p->root_worker; } static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { if (grpc_pollset_has_workers(p)) { grpc_pollset_worker *w = p->root_worker.next; remove_worker(p, w); return w; } else { return NULL; } } static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->next = &p->root_worker; worker->prev = worker->next->prev; worker->prev->next = worker->next->prev = worker; } static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->prev = &p->root_worker; worker->next = worker->prev->next; worker->prev->next = worker->next->prev = worker; } void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { /* pollset->mu already held */ if (specific_worker != NULL) { if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { for (specific_worker = p->root_worker.next; specific_worker != &p->root_worker; specific_worker = specific_worker->next) { grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd); } p->kicked_without_pollers = 1; } else if (gpr_tls_get(&g_current_thread_worker) != (gpr_intptr)specific_worker) { grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd); } } else if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) { specific_worker = pop_front_worker(p); if (specific_worker != NULL) { push_back_worker(p, specific_worker); grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd); } else { p->kicked_without_pollers = 1; } } } /* global state management */ void grpc_pollset_global_init(void) { gpr_tls_init(&g_current_thread_poller); grpc_wakeup_fd_global_init(); } void grpc_pollset_global_shutdown(void) { gpr_tls_destroy(&g_current_thread_poller); grpc_wakeup_fd_global_destroy(); } /* main interface */ static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null); void grpc_pollset_init(grpc_pollset *pollset) { gpr_mu_init(&pollset->mu); pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; pollset->in_flight_cbs = 0; pollset->shutting_down = 0; pollset->called_shutdown = 0; become_basic_pollset(pollset, NULL); } void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) { gpr_mu_lock(&pollset->mu); pollset->vtable->add_fd(pollset, fd, 1); /* the following (enabled only in debug) will reacquire and then release our lock - meaning that if the unlocking flag passed to del_fd above is not respected, the code will deadlock (in a way that we have a chance of debugging) */ #ifndef NDEBUG gpr_mu_lock(&pollset->mu); gpr_mu_unlock(&pollset->mu); #endif } void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) { gpr_mu_lock(&pollset->mu); pollset->vtable->del_fd(pollset, fd, 1); /* the following (enabled only in debug) will reacquire and then release our lock - meaning that if the unlocking flag passed to del_fd above is not respected, the code will deadlock (in a way that we have a chance of debugging) */ #ifndef NDEBUG gpr_mu_lock(&pollset->mu); gpr_mu_unlock(&pollset->mu); #endif } static void finish_shutdown(grpc_pollset *pollset) { pollset->vtable->finish_shutdown(pollset); pollset->shutdown_done_cb(pollset->shutdown_done_arg); } void grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec now, gpr_timespec deadline) { /* pollset->mu already held */ int added_worker = 0; /* this must happen before we (potentially) drop pollset->mu */ worker->next = worker->prev = NULL; /* TODO(ctiller): pool these */ grpc_wakeup_fd_init(&worker->wakeup_fd); if (grpc_maybe_call_delayed_callbacks(&pollset->mu, 1)) { goto done; } if (grpc_alarm_check(&pollset->mu, now, &deadline)) { goto done; } if (pollset->shutting_down) { goto done; } if (pollset->in_flight_cbs) { /* Give do_promote priority so we don't starve it out */ gpr_mu_unlock(&pollset->mu); gpr_mu_lock(&pollset->mu); goto done; } if (!pollset->kicked_without_pollers) { push_front_worker(pollset, worker); added_worker = 1; gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset); pollset->vtable->maybe_work(pollset, worker, deadline, now, 1); gpr_tls_set(&g_current_thread_poller, 0); } else { pollset->kicked_without_pollers = 0; } done: grpc_wakeup_fd_destroy(&worker->wakeup_fd); if (added_worker) { remove_worker(pollset, worker); } if (pollset->shutting_down) { if (grpc_pollset_has_workers(pollset)) { grpc_pollset_kick(pollset, NULL); } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) { pollset->called_shutdown = 1; gpr_mu_unlock(&pollset->mu); finish_shutdown(pollset); /* Continuing to access pollset here is safe -- it is the caller's * responsibility to not destroy when it has outstanding calls to * grpc_pollset_work. * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */ gpr_mu_lock(&pollset->mu); } } } void grpc_pollset_shutdown(grpc_pollset *pollset, void (*shutdown_done)(void *arg), void *shutdown_done_arg) { int call_shutdown = 0; gpr_mu_lock(&pollset->mu); GPR_ASSERT(!pollset->shutting_down); pollset->shutting_down = 1; if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 && !grpc_pollset_has_workers(pollset)) { pollset->called_shutdown = 1; call_shutdown = 1; } pollset->shutdown_done_cb = shutdown_done; pollset->shutdown_done_arg = shutdown_done_arg; grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); gpr_mu_unlock(&pollset->mu); if (call_shutdown) { finish_shutdown(pollset); } } void grpc_pollset_destroy(grpc_pollset *pollset) { GPR_ASSERT(pollset->shutting_down); GPR_ASSERT(pollset->in_flight_cbs == 0); GPR_ASSERT(!grpc_pollset_has_workers(pollset)); pollset->vtable->destroy(pollset); gpr_mu_destroy(&pollset->mu); } int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now) { gpr_timespec timeout; static const int max_spin_polling_us = 10; if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { return -1; } if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros( max_spin_polling_us, GPR_TIMESPAN))) <= 0) { return 0; } timeout = gpr_time_sub(deadline, now); return gpr_time_to_millis(gpr_time_add( timeout, gpr_time_from_nanos(GPR_NS_PER_SEC - 1, GPR_TIMESPAN))); } /* * basic_pollset - a vtable that provides polling for zero or one file * descriptor via poll() */ typedef struct grpc_unary_promote_args { const grpc_pollset_vtable *original_vtable; grpc_pollset *pollset; grpc_fd *fd; grpc_iomgr_closure promotion_closure; } grpc_unary_promote_args; static void basic_do_promote(void *args, int success) { grpc_unary_promote_args *up_args = args; const grpc_pollset_vtable *original_vtable = up_args->original_vtable; grpc_pollset *pollset = up_args->pollset; grpc_fd *fd = up_args->fd; int do_shutdown_cb = 0; /* * This is quite tricky. There are a number of cases to keep in mind here: * 1. fd may have been orphaned * 2. The pollset may no longer be a unary poller (and we can't let case #1 * leak to other pollset types!) * 3. pollset's fd (which may have changed) may have been orphaned * 4. The pollset may be shutting down. */ gpr_mu_lock(&pollset->mu); /* First we need to ensure that nobody is polling concurrently */ if (grpc_pollset_has_workers(pollset)) { grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); grpc_iomgr_add_callback(&up_args->promotion_closure); gpr_mu_unlock(&pollset->mu); return; } gpr_free(up_args); /* At this point the pollset may no longer be a unary poller. In that case * we should just call the right add function and be done. */ /* TODO(klempner): If we're not careful this could cause infinite recursion. * That's not a problem for now because empty_pollset has a trivial poller * and we don't have any mechanism to unbecome multipoller. */ pollset->in_flight_cbs--; if (pollset->shutting_down) { /* We don't care about this pollset anymore. */ if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) { GPR_ASSERT(!grpc_pollset_has_workers(pollset)); pollset->called_shutdown = 1; do_shutdown_cb = 1; } } else if (grpc_fd_is_orphaned(fd)) { /* Don't try to add it to anything, we'll drop our ref on it below */ } else if (pollset->vtable != original_vtable) { pollset->vtable->add_fd(pollset, fd, 0); } else if (fd != pollset->data.ptr) { grpc_fd *fds[2]; fds[0] = pollset->data.ptr; fds[1] = fd; if (fds[0] && !grpc_fd_is_orphaned(fds[0])) { grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds)); GRPC_FD_UNREF(fds[0], "basicpoll"); } else { /* old fd is orphaned and we haven't cleaned it up until now, so remain a * unary poller */ /* Note that it is possible that fds[1] is also orphaned at this point. * That's okay, we'll correct it at the next add or poll. */ if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll"); pollset->data.ptr = fd; GRPC_FD_REF(fd, "basicpoll"); } } gpr_mu_unlock(&pollset->mu); if (do_shutdown_cb) { pollset->shutdown_done_cb(pollset->shutdown_done_arg); } /* Matching ref in basic_pollset_add_fd */ GRPC_FD_UNREF(fd, "basicpoll_add"); } static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd, int and_unlock_pollset) { grpc_unary_promote_args *up_args; GPR_ASSERT(fd); if (fd == pollset->data.ptr) goto exit; if (!grpc_pollset_has_workers(pollset)) { /* Fast path -- no in flight cbs */ /* TODO(klempner): Comment this out and fix any test failures or establish * they are due to timing issues */ grpc_fd *fds[2]; fds[0] = pollset->data.ptr; fds[1] = fd; if (fds[0] == NULL) { pollset->data.ptr = fd; GRPC_FD_REF(fd, "basicpoll"); } else if (!grpc_fd_is_orphaned(fds[0])) { grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds)); GRPC_FD_UNREF(fds[0], "basicpoll"); } else { /* old fd is orphaned and we haven't cleaned it up until now, so remain a * unary poller */ GRPC_FD_UNREF(fds[0], "basicpoll"); pollset->data.ptr = fd; GRPC_FD_REF(fd, "basicpoll"); } goto exit; } /* Now we need to promote. This needs to happen when we're not polling. Since * this may be called from poll, the wait needs to happen asynchronously. */ GRPC_FD_REF(fd, "basicpoll_add"); pollset->in_flight_cbs++; up_args = gpr_malloc(sizeof(*up_args)); up_args->pollset = pollset; up_args->fd = fd; up_args->original_vtable = pollset->vtable; up_args->promotion_closure.cb = basic_do_promote; up_args->promotion_closure.cb_arg = up_args; grpc_iomgr_add_callback(&up_args->promotion_closure); grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); exit: if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); } } static void basic_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd, int and_unlock_pollset) { GPR_ASSERT(fd); if (fd == pollset->data.ptr) { GRPC_FD_UNREF(pollset->data.ptr, "basicpoll"); pollset->data.ptr = NULL; } if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); } } static void basic_pollset_maybe_work(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline, gpr_timespec now, int allow_synchronous_callback) { struct pollfd pfd[2]; grpc_fd *fd; grpc_fd_watcher fd_watcher; int timeout; int r; int nfds; fd = pollset->data.ptr; if (fd && grpc_fd_is_orphaned(fd)) { GRPC_FD_UNREF(fd, "basicpoll"); fd = pollset->data.ptr = NULL; } timeout = grpc_poll_deadline_to_millis_timeout(deadline, now); pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd); pfd[0].events = POLLIN; pfd[0].revents = 0; nfds = 1; if (fd) { pfd[1].fd = fd->fd; pfd[1].revents = 0; gpr_mu_unlock(&pollset->mu); pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher); if (pfd[1].events != 0) { nfds++; } } else { gpr_mu_unlock(&pollset->mu); } /* poll fd count (argument 2) is shortened by one if we have no events to poll on - such that it only includes the kicker */ r = grpc_poll_function(pfd, nfds, timeout); GRPC_TIMER_MARK(GRPC_PTAG_POLL_FINISHED, r); if (fd) { grpc_fd_end_poll(&fd_watcher, pfd[1].revents & POLLIN, pfd[1].revents & POLLOUT); } if (r < 0) { if (errno != EINTR) { gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); } } else if (r == 0) { /* do nothing */ } else { if (pfd[0].revents & POLLIN) { grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd); } if (nfds > 1) { if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) { grpc_fd_become_readable(fd, allow_synchronous_callback); } if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) { grpc_fd_become_writable(fd, allow_synchronous_callback); } } } gpr_mu_lock(&pollset->mu); } static void basic_pollset_destroy(grpc_pollset *pollset) { if (pollset->data.ptr != NULL) { GRPC_FD_UNREF(pollset->data.ptr, "basicpoll"); pollset->data.ptr = NULL; } } static const grpc_pollset_vtable basic_pollset = { basic_pollset_add_fd, basic_pollset_del_fd, basic_pollset_maybe_work, basic_pollset_destroy, basic_pollset_destroy}; static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) { pollset->vtable = &basic_pollset; pollset->data.ptr = fd_or_null; if (fd_or_null != NULL) { GRPC_FD_REF(fd_or_null, "basicpoll"); } } #endif /* GPR_POSIX_POLLSET */ grpc-0.11.1/src/core/iomgr/iocp_windows.h0000644000175000017500000000421712600663151020434 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H #define GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H #include #include "src/core/iomgr/socket_windows.h" void grpc_iocp_init(void); void grpc_iocp_kick(void); void grpc_iocp_shutdown(void); void grpc_iocp_add_socket(grpc_winsocket *); void grpc_socket_notify_on_write(grpc_winsocket *, void (*cb)(void *, int success), void *opaque); void grpc_socket_notify_on_read(grpc_winsocket *, void (*cb)(void *, int success), void *opaque); #endif /* GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H */ grpc-0.11.1/src/core/iomgr/tcp_windows.c0000644000175000017500000003140512600663151020262 0ustar apollockapollock/* * * 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 #ifdef GPR_WINSOCK_SOCKET #include "src/core/iomgr/sockaddr_win32.h" #include #include #include #include #include #include #include "src/core/iomgr/alarm.h" #include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/socket_windows.h" #include "src/core/iomgr/tcp_client.h" static int set_non_block(SOCKET sock) { int status; unsigned long param = 1; DWORD ret; status = WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, NULL, NULL); return status == 0; } static int set_dualstack(SOCKET sock) { int status; unsigned long param = 0; status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)¶m, sizeof(param)); return status == 0; } int grpc_tcp_prepare_socket(SOCKET sock) { if (!set_non_block(sock)) return 0; if (!set_dualstack(sock)) return 0; return 1; } typedef struct grpc_tcp { /* This is our C++ class derivation emulation. */ grpc_endpoint base; /* The one socket this endpoint is using. */ grpc_winsocket *socket; /* Refcounting how many operations are in progress. */ gpr_refcount refcount; grpc_iomgr_closure *read_cb; grpc_iomgr_closure *write_cb; gpr_slice read_slice; gpr_slice_buffer *write_slices; gpr_slice_buffer *read_slices; /* The IO Completion Port runs from another thread. We need some mechanism to protect ourselves when requesting a shutdown. */ gpr_mu mu; int shutting_down; char *peer_string; } grpc_tcp; static void tcp_free(grpc_tcp *tcp) { grpc_winsocket_destroy(tcp->socket); gpr_mu_destroy(&tcp->mu); gpr_free(tcp->peer_string); gpr_free(tcp); } /*#define GRPC_TCP_REFCOUNT_DEBUG*/ #ifdef GRPC_TCP_REFCOUNT_DEBUG #define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, reason, tcp->refcount.count, tcp->refcount.count - 1); if (gpr_unref(&tcp->refcount)) { tcp_free(tcp); } } static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, int line) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, reason, tcp->refcount.count, tcp->refcount.count + 1); gpr_ref(&tcp->refcount); } #else #define TCP_UNREF(tcp, reason) tcp_unref((tcp)) #define TCP_REF(tcp, reason) tcp_ref((tcp)) static void tcp_unref(grpc_tcp *tcp) { if (gpr_unref(&tcp->refcount)) { tcp_free(tcp); } } static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } #endif /* Asynchronous callback from the IOCP, or the background thread. */ static int on_read(grpc_tcp *tcp, int success) { grpc_winsocket *socket = tcp->socket; gpr_slice sub; gpr_slice *slice = NULL; size_t nslices = 0; grpc_winsocket_callback_info *info = &socket->read_info; int do_abort = 0; if (success) { if (socket->read_info.wsa_error != 0 && !tcp->shutting_down) { if (socket->read_info.wsa_error != WSAECONNRESET) { char *utf8_message = gpr_format_message(info->wsa_error); gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message); gpr_free(utf8_message); } success = 0; gpr_slice_unref(tcp->read_slice); } else { if (info->bytes_transfered != 0 && !tcp->shutting_down) { sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); gpr_slice_buffer_add(tcp->read_slices, sub); success = 1; } else { gpr_slice_unref(tcp->read_slice); success = 0; } } } return success; } static void on_read_cb(void *tcpp, int from_iocp) { grpc_tcp *tcp = tcpp; grpc_iomgr_closure *cb = tcp->read_cb; int success = on_read(tcp, from_iocp); tcp->read_cb = NULL; TCP_UNREF(tcp, "read"); if (cb) { cb->cb(cb->cb_arg, success); } } static grpc_endpoint_op_status win_read(grpc_endpoint *ep, gpr_slice_buffer *read_slices, grpc_iomgr_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *handle = tcp->socket; grpc_winsocket_callback_info *info = &handle->read_info; int status; DWORD bytes_read = 0; DWORD flags = 0; WSABUF buffer; if (tcp->shutting_down) { return GRPC_ENDPOINT_ERROR; } tcp->read_cb = cb; tcp->read_slices = read_slices; gpr_slice_buffer_reset_and_unref(read_slices); tcp->read_slice = gpr_slice_malloc(8192); buffer.len = GPR_SLICE_LENGTH(tcp->read_slice); buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice); /* First let's try a synchronous, non-blocking read. */ status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); /* Did we get data immediately ? Yay. */ if (info->wsa_error != WSAEWOULDBLOCK) { int ok; info->bytes_transfered = bytes_read; ok = on_read(tcp, 1); return ok ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; } TCP_REF(tcp, "read"); /* Otherwise, let's retry, by queuing a read. */ memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, &info->overlapped, NULL); if (status != 0) { int wsa_error = WSAGetLastError(); if (wsa_error != WSA_IO_PENDING) { int ok; info->wsa_error = wsa_error; ok = on_read(tcp, 1); return ok ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; } } grpc_socket_notify_on_read(tcp->socket, on_read_cb, tcp); return GRPC_ENDPOINT_PENDING; } /* Asynchronous callback from the IOCP, or the background thread. */ static void on_write(void *tcpp, int success) { grpc_tcp *tcp = (grpc_tcp *)tcpp; grpc_winsocket *handle = tcp->socket; grpc_winsocket_callback_info *info = &handle->write_info; grpc_iomgr_closure *cb; int do_abort = 0; gpr_mu_lock(&tcp->mu); cb = tcp->write_cb; tcp->write_cb = NULL; gpr_mu_unlock(&tcp->mu); if (success) { if (info->wsa_error != 0) { if (info->wsa_error != WSAECONNRESET) { char *utf8_message = gpr_format_message(info->wsa_error); gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message); gpr_free(utf8_message); } success = 0; } else { GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length); } } TCP_UNREF(tcp, "write"); cb->cb(cb->cb_arg, success); } /* Initiates a write. */ static grpc_endpoint_op_status win_write(grpc_endpoint *ep, gpr_slice_buffer *slices, grpc_iomgr_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *socket = tcp->socket; grpc_winsocket_callback_info *info = &socket->write_info; unsigned i; DWORD bytes_sent; int status; WSABUF local_buffers[16]; WSABUF *allocated = NULL; WSABUF *buffers = local_buffers; if (tcp->shutting_down) { return GRPC_ENDPOINT_ERROR; } tcp->write_cb = cb; tcp->write_slices = slices; if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) { buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count); allocated = buffers; } for (i = 0; i < tcp->write_slices->count; i++) { buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]); buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]); } /* First, let's try a synchronous, non-blocking write. */ status = WSASend(socket->socket, buffers, tcp->write_slices->count, &bytes_sent, 0, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy connection that has its send queue filled up. But if we don't, then we can avoid doing an async write operation at all. */ if (info->wsa_error != WSAEWOULDBLOCK) { grpc_endpoint_op_status ret = GRPC_ENDPOINT_ERROR; if (status == 0) { ret = GRPC_ENDPOINT_DONE; GPR_ASSERT(bytes_sent == tcp->write_slices->length); } else { if (socket->read_info.wsa_error != WSAECONNRESET) { char *utf8_message = gpr_format_message(info->wsa_error); gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message); gpr_free(utf8_message); } } if (allocated) gpr_free(allocated); return ret; } TCP_REF(tcp, "write"); /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same operation, this time asynchronously. */ memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED)); status = WSASend(socket->socket, buffers, tcp->write_slices->count, &bytes_sent, 0, &socket->write_info.overlapped, NULL); if (allocated) gpr_free(allocated); if (status != 0) { int wsa_error = WSAGetLastError(); if (wsa_error != WSA_IO_PENDING) { TCP_UNREF(tcp, "write"); return GRPC_ENDPOINT_ERROR; } } /* As all is now setup, we can now ask for the IOCP notification. It may trigger the callback immediately however, but no matter. */ grpc_socket_notify_on_write(socket, on_write, tcp); return GRPC_ENDPOINT_PENDING; } static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) { grpc_tcp *tcp; (void)ps; tcp = (grpc_tcp *)ep; grpc_iocp_add_socket(tcp->socket); } static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) { grpc_tcp *tcp; (void)pss; tcp = (grpc_tcp *)ep; grpc_iocp_add_socket(tcp->socket); } /* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks for the potential read and write operations. It is up to the caller to guarantee this isn't called in parallel to a read or write request, so we're not going to protect against these. However the IO Completion Port callback will happen from another thread, so we need to protect against concurrent access of the data structure in that regard. */ static void win_shutdown(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; gpr_mu_lock(&tcp->mu); /* At that point, what may happen is that we're already inside the IOCP callback. See the comments in on_read and on_write. */ tcp->shutting_down = 1; grpc_winsocket_shutdown(tcp->socket); gpr_mu_unlock(&tcp->mu); } static void win_destroy(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; TCP_UNREF(tcp, "destroy"); } static char *win_get_peer(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; return gpr_strdup(tcp->peer_string); } static grpc_endpoint_vtable vtable = { win_read, win_write, win_add_to_pollset, win_add_to_pollset_set, win_shutdown, win_destroy, win_get_peer}; grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); memset(tcp, 0, sizeof(grpc_tcp)); tcp->base.vtable = &vtable; tcp->socket = socket; gpr_mu_init(&tcp->mu); gpr_ref_init(&tcp->refcount, 1); tcp->peer_string = gpr_strdup(peer_string); return &tcp->base; } #endif /* GPR_WINSOCK_SOCKET */ grpc-0.11.1/src/core/iomgr/pollset_windows.h0000644000175000017500000000457012600663151021166 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H #include #include "src/core/iomgr/socket_windows.h" /* There isn't really any such thing as a pollset under Windows, due to the nature of the IO completion ports. A Windows "pollset" is merely a mutex used to synchronize with the IOCP, and workers are condition variables used to block threads until work is ready. */ typedef struct grpc_pollset_worker { gpr_cv cv; struct grpc_pollset_worker *next; struct grpc_pollset_worker *prev; } grpc_pollset_worker; typedef struct grpc_pollset { gpr_mu mu; int shutting_down; int kicked_without_pollers; grpc_pollset_worker root_worker; } grpc_pollset; #define GRPC_POLLSET_MU(pollset) (&(pollset)->mu) #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */ grpc-0.11.1/src/core/iomgr/wakeup_fd_nospecial.c0000644000175000017500000000403212600663151021720 0ustar apollockapollock/* * * 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. * */ /* * This is a dummy file to provide an invalid specialized_wakeup_fd_vtable on * systems without anything better than pipe. */ #include #ifdef GPR_POSIX_NO_SPECIAL_WAKEUP_FD #include "src/core/iomgr/wakeup_fd_posix.h" #include static int check_availability_invalid(void) { return 0; } const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { NULL, NULL, NULL, NULL, check_availability_invalid}; #endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */ grpc-0.11.1/src/core/iomgr/alarm_heap.c0000644000175000017500000001222012600663151020005 0ustar apollockapollock/* * * 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/iomgr/alarm_heap.h" #include #include #include /* Adjusts a heap so as to move a hole at position i closer to the root, until a suitable position is found for element t. Then, copies t into that position. This functor is called each time immediately after modifying a value in the underlying container, with the offset of the modified element as its argument. */ static void adjust_upwards(grpc_alarm **first, int i, grpc_alarm *t) { while (i > 0) { int parent = (i - 1) / 2; if (gpr_time_cmp(first[parent]->deadline, t->deadline) >= 0) break; first[i] = first[parent]; first[i]->heap_index = i; i = parent; } first[i] = t; t->heap_index = i; } /* Adjusts a heap so as to move a hole at position i farther away from the root, until a suitable position is found for element t. Then, copies t into that position. */ static void adjust_downwards(grpc_alarm **first, int i, int length, grpc_alarm *t) { for (;;) { int left_child = 1 + 2 * i; int right_child; int next_i; if (left_child >= length) break; right_child = left_child + 1; next_i = right_child < length && gpr_time_cmp(first[left_child]->deadline, first[right_child]->deadline) < 0 ? right_child : left_child; if (gpr_time_cmp(t->deadline, first[next_i]->deadline) >= 0) break; first[i] = first[next_i]; first[i]->heap_index = i; i = next_i; } first[i] = t; t->heap_index = i; } #define SHRINK_MIN_ELEMS 8 #define SHRINK_FULLNESS_FACTOR 2 static void maybe_shrink(grpc_alarm_heap *heap) { if (heap->alarm_count >= 8 && heap->alarm_count <= heap->alarm_capacity / SHRINK_FULLNESS_FACTOR / 2) { heap->alarm_capacity = heap->alarm_count * SHRINK_FULLNESS_FACTOR; heap->alarms = gpr_realloc(heap->alarms, heap->alarm_capacity * sizeof(grpc_alarm *)); } } static void note_changed_priority(grpc_alarm_heap *heap, grpc_alarm *alarm) { int i = alarm->heap_index; int parent = (i - 1) / 2; if (gpr_time_cmp(heap->alarms[parent]->deadline, alarm->deadline) < 0) { adjust_upwards(heap->alarms, i, alarm); } else { adjust_downwards(heap->alarms, i, heap->alarm_count, alarm); } } void grpc_alarm_heap_init(grpc_alarm_heap *heap) { memset(heap, 0, sizeof(*heap)); } void grpc_alarm_heap_destroy(grpc_alarm_heap *heap) { gpr_free(heap->alarms); } int grpc_alarm_heap_add(grpc_alarm_heap *heap, grpc_alarm *alarm) { if (heap->alarm_count == heap->alarm_capacity) { heap->alarm_capacity = GPR_MAX(heap->alarm_capacity + 1, heap->alarm_capacity * 3 / 2); heap->alarms = gpr_realloc(heap->alarms, heap->alarm_capacity * sizeof(grpc_alarm *)); } alarm->heap_index = heap->alarm_count; adjust_upwards(heap->alarms, heap->alarm_count, alarm); heap->alarm_count++; return alarm->heap_index == 0; } void grpc_alarm_heap_remove(grpc_alarm_heap *heap, grpc_alarm *alarm) { int i = alarm->heap_index; if (i == heap->alarm_count - 1) { heap->alarm_count--; maybe_shrink(heap); return; } heap->alarms[i] = heap->alarms[heap->alarm_count - 1]; heap->alarms[i]->heap_index = i; heap->alarm_count--; maybe_shrink(heap); note_changed_priority(heap, heap->alarms[i]); } int grpc_alarm_heap_is_empty(grpc_alarm_heap *heap) { return heap->alarm_count == 0; } grpc_alarm *grpc_alarm_heap_top(grpc_alarm_heap *heap) { return heap->alarms[0]; } void grpc_alarm_heap_pop(grpc_alarm_heap *heap) { grpc_alarm_heap_remove(heap, grpc_alarm_heap_top(heap)); } grpc-0.11.1/src/core/iomgr/socket_utils_posix.h0000644000175000017500000001135712600663151021665 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H #include #include /* a wrapper for accept or accept4 */ int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int nonblock, int cloexec); /* set a socket to non blocking mode */ int grpc_set_socket_nonblocking(int fd, int non_blocking); /* set a socket to close on exec */ int grpc_set_socket_cloexec(int fd, int close_on_exec); /* set a socket to reuse old addresses */ int grpc_set_socket_reuse_addr(int fd, int reuse); /* disable nagle */ int grpc_set_socket_low_latency(int fd, int low_latency); /* Returns true if this system can create AF_INET6 sockets bound to ::1. The value is probed once, and cached for the life of the process. This is more restrictive than checking for socket(AF_INET6) to succeed, because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port without a valid loopback interface. Rather than expose this half-broken state to library users, we turn off IPv6 sockets. */ int grpc_ipv6_loopback_available(void); /* Tries to set SO_NOSIGPIPE if available on this platform. Returns 1 on success, 0 on failure. If SO_NO_SIGPIPE is not available, returns 1. */ int grpc_set_socket_no_sigpipe_if_possible(int fd); /* An enum to keep track of IPv4/IPv6 socket modes. Currently, this information is only used when a socket is first created, but in the future we may wish to store it alongside the fd. This would let calls like sendto() know which family to use without asking the kernel first. */ typedef enum grpc_dualstack_mode { /* Uninitialized, or a non-IP socket. */ GRPC_DSMODE_NONE, /* AF_INET only. */ GRPC_DSMODE_IPV4, /* AF_INET6 only, because IPV6_V6ONLY could not be cleared. */ GRPC_DSMODE_IPV6, /* AF_INET6, which also supports ::ffff-mapped IPv4 addresses. */ GRPC_DSMODE_DUALSTACK } grpc_dualstack_mode; /* Only tests should use this flag. */ extern int grpc_forbid_dualstack_sockets_for_testing; /* Creates a new socket for connecting to (or listening on) an address. If addr is AF_INET6, this creates an IPv6 socket first. If that fails, and addr is within ::ffff:0.0.0.0/96, then it automatically falls back to an IPv4 socket. If addr is AF_INET, AF_UNIX, or anything else, then this is similar to calling socket() directly. Returns an fd on success, otherwise returns -1 with errno set to the result of a failed socket() call. The *dsmode output indicates which address family was actually created. The recommended way to use this is: - First convert to IPv6 using grpc_sockaddr_to_v4mapped(). - Create the socket. - If *dsmode is IPV4, use grpc_sockaddr_is_v4mapped() to convert back to IPv4, so that bind() or connect() see the correct family. Also, it's important to distinguish between DUALSTACK and IPV6 when listening on the [::] wildcard address. */ int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, int protocol, grpc_dualstack_mode *dsmode); #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H */ grpc-0.11.1/src/core/iomgr/endpoint_pair_posix.c0000644000175000017500000000556112600663151022003 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/endpoint_pair.h" #include #include #include #include #include #include "src/core/iomgr/tcp_posix.h" #include "src/core/support/string.h" #include #include #include static void create_sockets(int sv[2]) { int flags; GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); flags = fcntl(sv[0], F_GETFL, 0); GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0); flags = fcntl(sv[1], F_GETFL, 0); GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0); } grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size) { int sv[2]; grpc_endpoint_pair p; char *final_name; create_sockets(sv); gpr_asprintf(&final_name, "%s:client", name); p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size, "socketpair-server"); gpr_free(final_name); gpr_asprintf(&final_name, "%s:server", name); p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size, "socketpair-client"); gpr_free(final_name); return p; } #endif grpc-0.11.1/src/core/iomgr/wakeup_fd_pipe.c0000644000175000017500000000600512600663151020702 0ustar apollockapollock/* * * 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 #ifdef GPR_POSIX_WAKEUP_FD #include "src/core/iomgr/wakeup_fd_posix.h" #include #include #include #include "src/core/iomgr/socket_utils_posix.h" #include static void pipe_init(grpc_wakeup_fd *fd_info) { int pipefd[2]; /* TODO(klempner): Make this nonfatal */ GPR_ASSERT(0 == pipe(pipefd)); GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1)); GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1)); fd_info->read_fd = pipefd[0]; fd_info->write_fd = pipefd[1]; } static void pipe_consume(grpc_wakeup_fd *fd_info) { char buf[128]; int r; for (;;) { r = read(fd_info->read_fd, buf, sizeof(buf)); if (r > 0) continue; if (r == 0) return; switch (errno) { case EAGAIN: return; case EINTR: continue; default: gpr_log(GPR_ERROR, "error reading pipe: %s", strerror(errno)); return; } } } static void pipe_wakeup(grpc_wakeup_fd *fd_info) { char c = 0; while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR) ; } static void pipe_destroy(grpc_wakeup_fd *fd_info) { close(fd_info->read_fd); close(fd_info->write_fd); } static int pipe_check_availability(void) { /* Assume that pipes are always available. */ return 1; } const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = { pipe_init, pipe_consume, pipe_wakeup, pipe_destroy, pipe_check_availability}; #endif /* GPR_POSIX_WAKUP_FD */ grpc-0.11.1/src/core/iomgr/alarm_internal.h0000644000175000017500000000506712600663151020724 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H #define GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H #include #include /* iomgr internal api for dealing with alarms */ /* Check for alarms to be run, and run them. Return non zero if alarm callbacks were executed. Drops drop_mu if it is non-null before executing callbacks. If next is non-null, TRY to update *next with the next running alarm IF that alarm occurs before *next current value. *next is never guaranteed to be updated on any given execution; however, with high probability at least one thread in the system will see an update at any time slice. */ int grpc_alarm_check(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next); void grpc_alarm_list_init(gpr_timespec now); void grpc_alarm_list_shutdown(void); gpr_timespec grpc_alarm_list_next_timeout(void); /* the following must be implemented by each iomgr implementation */ void grpc_kick_poller(void); #endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H */ grpc-0.11.1/src/core/tsi/0000755000175000017500000000000012600663151015235 5ustar apollockapollockgrpc-0.11.1/src/core/tsi/fake_transport_security.h0000644000175000017500000000466612600663151022373 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H #define GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H #include "src/core/tsi/transport_security_interface.h" #ifdef __cplusplus extern "C" { #endif /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */ #define TSI_FAKE_CERTIFICATE_TYPE "FAKE" /* Creates a fake handshaker that will create a fake frame protector. No cryptography is performed in these objects. They just simulate handshake messages going back and forth for the handshaker and do some framing on cleartext data for the protector. */ tsi_handshaker* tsi_create_fake_handshaker(int is_client); /* Creates a protector directly without going through the handshake phase. */ tsi_frame_protector* tsi_create_fake_protector( size_t* max_protected_frame_size); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */ grpc-0.11.1/src/core/tsi/transport_security.h0000644000175000017500000001141312600663151021371 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H #define GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H #include "src/core/tsi/transport_security_interface.h" #ifdef __cplusplus extern "C" { #endif extern int tsi_tracing_enabled; /* Base for tsi_frame_protector implementations. See transport_security_interface.h for documentation. */ typedef struct { tsi_result (*protect)(tsi_frame_protector* self, const unsigned char* unprotected_bytes, size_t* unprotected_bytes_size, unsigned char* protected_output_frames, size_t* protected_output_frames_size); tsi_result (*protect_flush)(tsi_frame_protector* self, unsigned char* protected_output_frames, size_t* protected_output_frames_size, size_t* still_pending_size); tsi_result (*unprotect)(tsi_frame_protector* self, const unsigned char* protected_frames_bytes, size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, size_t* unprotected_bytes_size); void (*destroy)(tsi_frame_protector* self); } tsi_frame_protector_vtable; struct tsi_frame_protector { const tsi_frame_protector_vtable* vtable; }; /* Base for tsi_handshaker implementations. See transport_security_interface.h for documentation. */ typedef struct { tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker* self, unsigned char* bytes, size_t* bytes_size); tsi_result (*process_bytes_from_peer)(tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size); tsi_result (*get_result)(tsi_handshaker* self); tsi_result (*extract_peer)(tsi_handshaker* self, tsi_peer* peer); tsi_result (*create_frame_protector)(tsi_handshaker* self, size_t* max_protected_frame_size, tsi_frame_protector** protector); void (*destroy)(tsi_handshaker* self); } tsi_handshaker_vtable; struct tsi_handshaker { const tsi_handshaker_vtable* vtable; int frame_protector_created; }; /* Peer and property construction/destruction functions. */ tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer); tsi_peer_property tsi_init_peer_property(void); void tsi_peer_property_destruct(tsi_peer_property* property); tsi_result tsi_construct_string_peer_property(const char* name, const char* value, size_t value_length, tsi_peer_property* property); tsi_result tsi_construct_allocated_string_peer_property( const char* name, size_t value_length, tsi_peer_property* property); tsi_result tsi_construct_string_peer_property_from_cstring( const char* name, const char* value, tsi_peer_property* property); /* Utils. */ char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */ #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H */ grpc-0.11.1/src/core/tsi/ssl_transport_security.c0000644000175000017500000014436512600663151022262 0ustar apollockapollock/* * * 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/tsi/ssl_transport_security.h" #include #include #include #include #include #include #include "src/core/tsi/transport_security.h" #include #include /* For OPENSSL_free */ #include #include #include #include /* --- Constants. ---*/ #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024 /* Putting a macro like this and littering the source file with #if is really bad practice. TODO(jboeuf): refactor all the #if / #endif in a separate module. */ #ifndef TSI_OPENSSL_ALPN_SUPPORT #define TSI_OPENSSL_ALPN_SUPPORT 1 #endif /* TODO(jboeuf): I have not found a way to get this number dynamically from the SSL structure. This is what we would ultimately want though... */ #define TSI_SSL_MAX_PROTECTION_OVERHEAD 100 /* --- Structure definitions. ---*/ struct tsi_ssl_handshaker_factory { tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory* self, const char* server_name_indication, tsi_handshaker** handshaker); void (*destroy)(tsi_ssl_handshaker_factory* self); }; typedef struct { tsi_ssl_handshaker_factory base; SSL_CTX* ssl_context; unsigned char* alpn_protocol_list; size_t alpn_protocol_list_length; } tsi_ssl_client_handshaker_factory; typedef struct { tsi_ssl_handshaker_factory base; /* Several contexts to support SNI. The tsi_peer array contains the subject names of the server certificates associated with the contexts at the same index. */ SSL_CTX** ssl_contexts; tsi_peer* ssl_context_x509_subject_names; size_t ssl_context_count; unsigned char* alpn_protocol_list; size_t alpn_protocol_list_length; } tsi_ssl_server_handshaker_factory; typedef struct { tsi_handshaker base; SSL* ssl; BIO* into_ssl; BIO* from_ssl; tsi_result result; } tsi_ssl_handshaker; typedef struct { tsi_frame_protector base; SSL* ssl; BIO* into_ssl; BIO* from_ssl; unsigned char* buffer; size_t buffer_size; size_t buffer_offset; } tsi_ssl_frame_protector; /* --- Library Initialization. ---*/ static gpr_once init_openssl_once = GPR_ONCE_INIT; static gpr_mu* openssl_mutexes = NULL; static void openssl_locking_cb(int mode, int type, const char* file, int line) { if (mode & CRYPTO_LOCK) { gpr_mu_lock(&openssl_mutexes[type]); } else { gpr_mu_unlock(&openssl_mutexes[type]); } } static unsigned long openssl_thread_id_cb(void) { return (unsigned long)gpr_thd_currentid(); } static void init_openssl(void) { int i; SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); openssl_mutexes = malloc(CRYPTO_num_locks() * sizeof(gpr_mu)); GPR_ASSERT(openssl_mutexes != NULL); for (i = 0; i < CRYPTO_num_locks(); i++) { gpr_mu_init(&openssl_mutexes[i]); } CRYPTO_set_locking_callback(openssl_locking_cb); CRYPTO_set_id_callback(openssl_thread_id_cb); } /* --- Ssl utils. ---*/ static const char* ssl_error_string(int error) { switch (error) { case SSL_ERROR_NONE: return "SSL_ERROR_NONE"; case SSL_ERROR_ZERO_RETURN: return "SSL_ERROR_ZERO_RETURN"; case SSL_ERROR_WANT_READ: return "SSL_ERROR_WANT_READ"; case SSL_ERROR_WANT_WRITE: return "SSL_ERROR_WANT_WRITE"; case SSL_ERROR_WANT_CONNECT: return "SSL_ERROR_WANT_CONNECT"; case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT"; case SSL_ERROR_WANT_X509_LOOKUP: return "SSL_ERROR_WANT_X509_LOOKUP"; case SSL_ERROR_SYSCALL: return "SSL_ERROR_SYSCALL"; case SSL_ERROR_SSL: return "SSL_ERROR_SSL"; default: return "Unknown error"; } } /* TODO(jboeuf): Remove when we are past the debugging phase with this code. */ static void ssl_log_where_info(const SSL* ssl, int where, int flag, const char* msg) { if ((where & flag) && tsi_tracing_enabled) { gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg, SSL_state_string_long(ssl), SSL_state_string(ssl)); } } /* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */ static void ssl_info_callback(const SSL* ssl, int where, int ret) { if (ret == 0) { gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n"); return; } ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP"); ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START"); ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE"); } /* Returns 1 if name looks like an IP address, 0 otherwise. This is a very rough heuristic as it does not handle IPV6 or things like: 0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */ static int looks_like_ip_address(const char* name) { size_t i; size_t dot_count = 0; size_t num_size = 0; for (i = 0; i < strlen(name); i++) { if (name[i] >= '0' && name[i] <= '9') { if (num_size > 3) return 0; num_size++; } else if (name[i] == '.') { if (dot_count > 3 || num_size == 0) return 0; dot_count++; num_size = 0; } else { return 0; } } if (dot_count < 3 || num_size == 0) return 0; return 1; } /* Gets the subject CN from an X509 cert. */ static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8, size_t* utf8_size) { int common_name_index = -1; X509_NAME_ENTRY* common_name_entry = NULL; ASN1_STRING* common_name_asn1 = NULL; X509_NAME* subject_name = X509_get_subject_name(cert); int utf8_returned_size = 0; if (subject_name == NULL) { gpr_log(GPR_ERROR, "Could not get subject name from certificate."); return TSI_NOT_FOUND; } common_name_index = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1); if (common_name_index == -1) { gpr_log(GPR_ERROR, "Could not get common name of subject from certificate."); return TSI_NOT_FOUND; } common_name_entry = X509_NAME_get_entry(subject_name, common_name_index); if (common_name_entry == NULL) { gpr_log(GPR_ERROR, "Could not get common name entry from certificate."); return TSI_INTERNAL_ERROR; } common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); if (common_name_asn1 == NULL) { gpr_log(GPR_ERROR, "Could not get common name entry asn1 from certificate."); return TSI_INTERNAL_ERROR; } utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1); if (utf8_returned_size < 0) { gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string."); return TSI_OUT_OF_RESOURCES; } *utf8_size = utf8_returned_size; return TSI_OK; } /* Gets the subject CN of an X509 cert as a tsi_peer_property. */ static tsi_result peer_property_from_x509_common_name( X509* cert, tsi_peer_property* property) { unsigned char* common_name; size_t common_name_size; tsi_result result = ssl_get_x509_common_name(cert, &common_name, &common_name_size); if (result != TSI_OK) { if (result == TSI_NOT_FOUND) { common_name = NULL; common_name_size = 0; } else { return result; } } result = tsi_construct_string_peer_property( TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, common_name == NULL ? "" : (const char*)common_name, common_name_size, property); OPENSSL_free(common_name); return result; } /* Gets the subject SANs from an X509 cert as a tsi_peer_property. */ static tsi_result add_subject_alt_names_properties_to_peer( tsi_peer* peer, GENERAL_NAMES* subject_alt_names, int subject_alt_name_count) { int i; tsi_result result = TSI_OK; /* Reset for DNS entries filtering. */ peer->property_count -= subject_alt_name_count; for (i = 0; i < subject_alt_name_count; i++) { GENERAL_NAME* subject_alt_name = sk_GENERAL_NAME_value(subject_alt_names, i); /* Filter out the non-dns entries names. */ if (subject_alt_name->type == GEN_DNS) { unsigned char* dns_name = NULL; int dns_name_size = ASN1_STRING_to_UTF8(&dns_name, subject_alt_name->d.dNSName); if (dns_name_size < 0) { gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string."); result = TSI_INTERNAL_ERROR; break; } result = tsi_construct_string_peer_property( TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char*)dns_name, dns_name_size, &peer->properties[peer->property_count++]); OPENSSL_free(dns_name); if (result != TSI_OK) break; } } return result; } /* Gets information about the peer's X509 cert as a tsi_peer object. */ static tsi_result peer_from_x509(X509* cert, int include_certificate_type, tsi_peer* peer) { /* TODO(jboeuf): Maybe add more properties. */ GENERAL_NAMES* subject_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0); int subject_alt_name_count = (subject_alt_names != NULL) ? sk_GENERAL_NAME_num(subject_alt_names) : 0; size_t property_count = (include_certificate_type ? 1 : 0) + 1 /* common name */ + subject_alt_name_count; tsi_result result = tsi_construct_peer(property_count, peer); if (result != TSI_OK) return result; do { if (include_certificate_type) { result = tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, &peer->properties[0]); if (result != TSI_OK) break; } result = peer_property_from_x509_common_name( cert, &peer->properties[include_certificate_type ? 1 : 0]); if (result != TSI_OK) break; if (subject_alt_name_count != 0) { result = add_subject_alt_names_properties_to_peer(peer, subject_alt_names, subject_alt_name_count); if (result != TSI_OK) break; } } while (0); if (subject_alt_names != NULL) { sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free); } if (result != TSI_OK) tsi_peer_destruct(peer); return result; } /* Logs the SSL error stack. */ static void log_ssl_error_stack(void) { unsigned long err; while ((err = ERR_get_error()) != 0) { char details[256]; ERR_error_string_n(err, details, sizeof(details)); gpr_log(GPR_ERROR, "%s", details); } } /* Performs an SSL_read and handle errors. */ static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes, size_t* unprotected_bytes_size) { int read_from_ssl = SSL_read(ssl, unprotected_bytes, *unprotected_bytes_size); if (read_from_ssl == 0) { gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly."); return TSI_INTERNAL_ERROR; } if (read_from_ssl < 0) { read_from_ssl = SSL_get_error(ssl, read_from_ssl); switch (read_from_ssl) { case SSL_ERROR_WANT_READ: /* We need more data to finish the frame. */ *unprotected_bytes_size = 0; return TSI_OK; case SSL_ERROR_WANT_WRITE: gpr_log( GPR_ERROR, "Peer tried to renegotiate SSL connection. This is unsupported."); return TSI_UNIMPLEMENTED; case SSL_ERROR_SSL: gpr_log(GPR_ERROR, "Corruption detected."); log_ssl_error_stack(); return TSI_DATA_CORRUPTED; default: gpr_log(GPR_ERROR, "SSL_read failed with error %s.", ssl_error_string(read_from_ssl)); return TSI_PROTOCOL_FAILURE; } } *unprotected_bytes_size = read_from_ssl; return TSI_OK; } /* Performs an SSL_write and handle errors. */ static tsi_result do_ssl_write(SSL* ssl, unsigned char* unprotected_bytes, size_t unprotected_bytes_size) { int ssl_write_result = SSL_write(ssl, unprotected_bytes, unprotected_bytes_size); if (ssl_write_result < 0) { ssl_write_result = SSL_get_error(ssl, ssl_write_result); if (ssl_write_result == SSL_ERROR_WANT_READ) { gpr_log(GPR_ERROR, "Peer tried to renegotiate SSL connection. This is unsupported."); return TSI_UNIMPLEMENTED; } else { gpr_log(GPR_ERROR, "SSL_write failed with error %s.", ssl_error_string(ssl_write_result)); return TSI_INTERNAL_ERROR; } } return TSI_OK; } /* Loads an in-memory PEM certificate chain into the SSL context. */ static tsi_result ssl_ctx_use_certificate_chain( SSL_CTX* context, const unsigned char* pem_cert_chain, size_t pem_cert_chain_size) { tsi_result result = TSI_OK; X509* certificate = NULL; BIO* pem = BIO_new_mem_buf((void*)pem_cert_chain, pem_cert_chain_size); if (pem == NULL) return TSI_OUT_OF_RESOURCES; do { certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, ""); if (certificate == NULL) { result = TSI_INVALID_ARGUMENT; break; } if (!SSL_CTX_use_certificate(context, certificate)) { result = TSI_INVALID_ARGUMENT; break; } while (1) { X509* certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, ""); if (certificate_authority == NULL) { ERR_clear_error(); break; /* Done reading. */ } if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) { X509_free(certificate_authority); result = TSI_INVALID_ARGUMENT; break; } /* We don't need to free certificate_authority as its ownership has been transfered to the context. That is not the case for certificate though. */ } } while (0); if (certificate != NULL) X509_free(certificate); BIO_free(pem); return result; } /* Loads an in-memory PEM private key into the SSL context. */ static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, const unsigned char* pem_key, size_t pem_key_size) { tsi_result result = TSI_OK; EVP_PKEY* private_key = NULL; BIO* pem = BIO_new_mem_buf((void*)pem_key, pem_key_size); if (pem == NULL) return TSI_OUT_OF_RESOURCES; do { private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, ""); if (private_key == NULL) { result = TSI_INVALID_ARGUMENT; break; } if (!SSL_CTX_use_PrivateKey(context, private_key)) { result = TSI_INVALID_ARGUMENT; break; } } while (0); if (private_key != NULL) EVP_PKEY_free(private_key); BIO_free(pem); return result; } /* Loads in-memory PEM verification certs into the SSL context and optionally returns the verification cert names (root_names can be NULL). */ static tsi_result ssl_ctx_load_verification_certs( SSL_CTX* context, const unsigned char* pem_roots, size_t pem_roots_size, STACK_OF(X509_NAME) * *root_names) { tsi_result result = TSI_OK; size_t num_roots = 0; X509* root = NULL; X509_NAME* root_name = NULL; BIO* pem = BIO_new_mem_buf((void*)pem_roots, pem_roots_size); X509_STORE* root_store = SSL_CTX_get_cert_store(context); if (root_store == NULL) return TSI_INVALID_ARGUMENT; if (pem == NULL) return TSI_OUT_OF_RESOURCES; if (root_names != NULL) { *root_names = sk_X509_NAME_new_null(); if (*root_names == NULL) return TSI_OUT_OF_RESOURCES; } while (1) { root = PEM_read_bio_X509_AUX(pem, NULL, NULL, ""); if (root == NULL) { ERR_clear_error(); break; /* We're at the end of stream. */ } if (root_names != NULL) { root_name = X509_get_subject_name(root); if (root_name == NULL) { gpr_log(GPR_ERROR, "Could not get name from root certificate."); result = TSI_INVALID_ARGUMENT; break; } root_name = X509_NAME_dup(root_name); if (root_name == NULL) { result = TSI_OUT_OF_RESOURCES; break; } sk_X509_NAME_push(*root_names, root_name); root_name = NULL; } if (!X509_STORE_add_cert(root_store, root)) { gpr_log(GPR_ERROR, "Could not add root certificate to ssl context."); result = TSI_INTERNAL_ERROR; break; } X509_free(root); num_roots++; } if (num_roots == 0) { gpr_log(GPR_ERROR, "Could not load any root certificate."); result = TSI_INVALID_ARGUMENT; } if (result != TSI_OK) { if (root != NULL) X509_free(root); if (root_names != NULL) { sk_X509_NAME_pop_free(*root_names, X509_NAME_free); *root_names = NULL; if (root_name != NULL) X509_NAME_free(root_name); } } BIO_free(pem); return result; } /* Populates the SSL context with a private key and a cert chain, and sets the cipher list and the ephemeral ECDH key. */ static tsi_result populate_ssl_context( SSL_CTX* context, const unsigned char* pem_private_key, size_t pem_private_key_size, const unsigned char* pem_certificate_chain, size_t pem_certificate_chain_size, const char* cipher_list) { tsi_result result = TSI_OK; if (pem_certificate_chain != NULL) { result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain, pem_certificate_chain_size); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Invalid cert chain file."); return result; } } if (pem_private_key != NULL) { result = ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size); if (result != TSI_OK || !SSL_CTX_check_private_key(context)) { gpr_log(GPR_ERROR, "Invalid private key."); return result != TSI_OK ? result : TSI_INVALID_ARGUMENT; } } if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) { gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list); return TSI_INVALID_ARGUMENT; } { EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) { gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key."); EC_KEY_free(ecdh); return TSI_INTERNAL_ERROR; } SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); EC_KEY_free(ecdh); } return TSI_OK; } /* Extracts the CN and the SANs from an X509 cert as a peer object. */ static tsi_result extract_x509_subject_names_from_pem_cert( const unsigned char* pem_cert, size_t pem_cert_size, tsi_peer* peer) { tsi_result result = TSI_OK; X509* cert = NULL; BIO* pem = BIO_new_mem_buf((void*)pem_cert, pem_cert_size); if (pem == NULL) return TSI_OUT_OF_RESOURCES; cert = PEM_read_bio_X509(pem, NULL, NULL, ""); if (cert == NULL) { gpr_log(GPR_ERROR, "Invalid certificate"); result = TSI_INVALID_ARGUMENT; } else { result = peer_from_x509(cert, 0, peer); } if (cert != NULL) X509_free(cert); BIO_free(pem); return result; } /* Builds the alpn protocol name list according to rfc 7301. */ static tsi_result build_alpn_protocol_name_list( const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, unsigned char** protocol_name_list, size_t* protocol_name_list_length) { uint16_t i; unsigned char* current; *protocol_name_list = NULL; *protocol_name_list_length = 0; if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT; for (i = 0; i < num_alpn_protocols; i++) { if (alpn_protocols_lengths[i] == 0) { gpr_log(GPR_ERROR, "Invalid 0-length protocol name."); return TSI_INVALID_ARGUMENT; } *protocol_name_list_length += alpn_protocols_lengths[i] + 1; } *protocol_name_list = malloc(*protocol_name_list_length); if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES; current = *protocol_name_list; for (i = 0; i < num_alpn_protocols; i++) { *(current++) = alpn_protocols_lengths[i]; memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]); current += alpn_protocols_lengths[i]; } /* Safety check. */ if ((current < *protocol_name_list) || ((gpr_uintptr)(current - *protocol_name_list) != *protocol_name_list_length)) { return TSI_INTERNAL_ERROR; } return TSI_OK; } /* --- tsi_frame_protector methods implementation. ---*/ static tsi_result ssl_protector_protect(tsi_frame_protector* self, const unsigned char* unprotected_bytes, size_t* unprotected_bytes_size, unsigned char* protected_output_frames, size_t* protected_output_frames_size) { tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; int read_from_ssl; size_t available; tsi_result result = TSI_OK; /* First see if we have some pending data in the SSL BIO. */ size_t pending_in_ssl = BIO_pending(impl->from_ssl); if (pending_in_ssl > 0) { *unprotected_bytes_size = 0; read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, *protected_output_frames_size); if (read_from_ssl < 0) { gpr_log(GPR_ERROR, "Could not read from BIO even though some data is pending"); return TSI_INTERNAL_ERROR; } *protected_output_frames_size = read_from_ssl; return TSI_OK; } /* Now see if we can send a complete frame. */ available = impl->buffer_size - impl->buffer_offset; if (available > *unprotected_bytes_size) { /* If we cannot, just copy the data in our internal buffer. */ memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, *unprotected_bytes_size); impl->buffer_offset += *unprotected_bytes_size; *protected_output_frames_size = 0; return TSI_OK; } /* If we can, prepare the buffer, send it to SSL_write and read. */ memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available); result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size); if (result != TSI_OK) return result; read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, *protected_output_frames_size); if (read_from_ssl < 0) { gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); return TSI_INTERNAL_ERROR; } *protected_output_frames_size = read_from_ssl; *unprotected_bytes_size = available; impl->buffer_offset = 0; return TSI_OK; } static tsi_result ssl_protector_protect_flush( tsi_frame_protector* self, unsigned char* protected_output_frames, size_t* protected_output_frames_size, size_t* still_pending_size) { tsi_result result = TSI_OK; tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; int read_from_ssl = 0; if (impl->buffer_offset != 0) { result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset); if (result != TSI_OK) return result; impl->buffer_offset = 0; } *still_pending_size = BIO_pending(impl->from_ssl); if (*still_pending_size == 0) return TSI_OK; read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, *protected_output_frames_size); if (read_from_ssl <= 0) { gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); return TSI_INTERNAL_ERROR; } *protected_output_frames_size = read_from_ssl; *still_pending_size = BIO_pending(impl->from_ssl); return TSI_OK; } static tsi_result ssl_protector_unprotect( tsi_frame_protector* self, const unsigned char* protected_frames_bytes, size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, size_t* unprotected_bytes_size) { tsi_result result = TSI_OK; int written_into_ssl = 0; size_t output_bytes_size = *unprotected_bytes_size; size_t output_bytes_offset = 0; tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; /* First, try to read remaining data from ssl. */ result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); if (result != TSI_OK) return result; if (*unprotected_bytes_size == output_bytes_size) { /* We have read everything we could and cannot process any more input. */ *protected_frames_bytes_size = 0; return TSI_OK; } output_bytes_offset = *unprotected_bytes_size; unprotected_bytes += output_bytes_offset; *unprotected_bytes_size = output_bytes_size - output_bytes_offset; /* Then, try to write some data to ssl. */ written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes, *protected_frames_bytes_size); if (written_into_ssl < 0) { gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d", written_into_ssl); return TSI_INTERNAL_ERROR; } *protected_frames_bytes_size = written_into_ssl; /* Now try to read some data again. */ result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); if (result == TSI_OK) { /* Don't forget to output the total number of bytes read. */ *unprotected_bytes_size += output_bytes_offset; } return result; } static void ssl_protector_destroy(tsi_frame_protector* self) { tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; if (impl->buffer != NULL) free(impl->buffer); if (impl->ssl != NULL) SSL_free(impl->ssl); free(self); } static const tsi_frame_protector_vtable frame_protector_vtable = { ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect, ssl_protector_destroy, }; /* --- tsi_handshaker methods implementation. ---*/ static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self, unsigned char* bytes, size_t* bytes_size) { tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; int bytes_read_from_ssl = 0; if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 || *bytes_size > INT_MAX) { return TSI_INVALID_ARGUMENT; } bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, *bytes_size); if (bytes_read_from_ssl < 0) { *bytes_size = 0; if (!BIO_should_retry(impl->from_ssl)) { impl->result = TSI_INTERNAL_ERROR; return impl->result; } else { return TSI_OK; } } *bytes_size = (size_t)bytes_read_from_ssl; return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA; } static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) { tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) && SSL_is_init_finished(impl->ssl)) { impl->result = TSI_OK; } return impl->result; } static tsi_result ssl_handshaker_process_bytes_from_peer( tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) { tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; int bytes_written_into_ssl_size = 0; if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) { return TSI_INVALID_ARGUMENT; } bytes_written_into_ssl_size = BIO_write(impl->into_ssl, bytes, *bytes_size); if (bytes_written_into_ssl_size < 0) { gpr_log(GPR_ERROR, "Could not write to memory BIO."); impl->result = TSI_INTERNAL_ERROR; return impl->result; } *bytes_size = bytes_written_into_ssl_size; if (!tsi_handshaker_is_in_progress(self)) { impl->result = TSI_OK; return impl->result; } else { /* Get ready to get some bytes from SSL. */ int ssl_result = SSL_do_handshake(impl->ssl); ssl_result = SSL_get_error(impl->ssl, ssl_result); switch (ssl_result) { case SSL_ERROR_WANT_READ: if (BIO_pending(impl->from_ssl) == 0) { /* We need more data. */ return TSI_INCOMPLETE_DATA; } else { return TSI_OK; } case SSL_ERROR_NONE: return TSI_OK; default: { char err_str[256]; ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str)); gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.", ssl_error_string(ssl_result), err_str); impl->result = TSI_PROTOCOL_FAILURE; return impl->result; } } } } static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) { tsi_result result = TSI_OK; const unsigned char* alpn_selected = NULL; unsigned int alpn_selected_len; tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; X509* peer_cert = SSL_get_peer_certificate(impl->ssl); if (peer_cert != NULL) { result = peer_from_x509(peer_cert, 1, peer); X509_free(peer_cert); if (result != TSI_OK) return result; } #if TSI_OPENSSL_ALPN_SUPPORT SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len); #endif /* TSI_OPENSSL_ALPN_SUPPORT */ if (alpn_selected == NULL) { /* Try npn. */ SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected, &alpn_selected_len); } if (alpn_selected != NULL) { size_t i; tsi_peer_property* new_properties = calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1)); if (new_properties == NULL) return TSI_OUT_OF_RESOURCES; for (i = 0; i < peer->property_count; i++) { new_properties[i] = peer->properties[i]; } result = tsi_construct_string_peer_property( TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char*)alpn_selected, alpn_selected_len, &new_properties[peer->property_count]); if (result != TSI_OK) { free(new_properties); return result; } if (peer->properties != NULL) free(peer->properties); peer->property_count++; peer->properties = new_properties; } return result; } static tsi_result ssl_handshaker_create_frame_protector( tsi_handshaker* self, size_t* max_output_protected_frame_size, tsi_frame_protector** protector) { size_t actual_max_output_protected_frame_size = TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; tsi_ssl_frame_protector* protector_impl = calloc(1, sizeof(tsi_ssl_frame_protector)); if (protector_impl == NULL) { return TSI_OUT_OF_RESOURCES; } if (max_output_protected_frame_size != NULL) { if (*max_output_protected_frame_size > TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) { *max_output_protected_frame_size = TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; } else if (*max_output_protected_frame_size < TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) { *max_output_protected_frame_size = TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND; } actual_max_output_protected_frame_size = *max_output_protected_frame_size; } protector_impl->buffer_size = actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD; protector_impl->buffer = malloc(protector_impl->buffer_size); if (protector_impl->buffer == NULL) { gpr_log(GPR_ERROR, "Could not allocated buffer for tsi_ssl_frame_protector."); free(protector_impl); return TSI_INTERNAL_ERROR; } /* Transfer ownership of ssl to the frame protector. It is OK as the caller * cannot call anything else but destroy on the handshaker after this call. */ protector_impl->ssl = impl->ssl; impl->ssl = NULL; protector_impl->into_ssl = impl->into_ssl; protector_impl->from_ssl = impl->from_ssl; protector_impl->base.vtable = &frame_protector_vtable; *protector = &protector_impl->base; return TSI_OK; } static void ssl_handshaker_destroy(tsi_handshaker* self) { tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; SSL_free(impl->ssl); /* The BIO objects are owned by ssl */ free(impl); } static const tsi_handshaker_vtable handshaker_vtable = { ssl_handshaker_get_bytes_to_send_to_peer, ssl_handshaker_process_bytes_from_peer, ssl_handshaker_get_result, ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector, ssl_handshaker_destroy, }; /* --- tsi_ssl_handshaker_factory common methods. --- */ tsi_result tsi_ssl_handshaker_factory_create_handshaker( tsi_ssl_handshaker_factory* self, const char* server_name_indication, tsi_handshaker** handshaker) { if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT; return self->create_handshaker(self, server_name_indication, handshaker); } void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self) { if (self == NULL) return; self->destroy(self); } static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client, const char* server_name_indication, tsi_handshaker** handshaker) { SSL* ssl = SSL_new(ctx); BIO* into_ssl = NULL; BIO* from_ssl = NULL; tsi_ssl_handshaker* impl = NULL; *handshaker = NULL; if (ctx == NULL) { gpr_log(GPR_ERROR, "SSL Context is null. Should never happen."); return TSI_INTERNAL_ERROR; } if (ssl == NULL) { return TSI_OUT_OF_RESOURCES; } SSL_set_info_callback(ssl, ssl_info_callback); into_ssl = BIO_new(BIO_s_mem()); from_ssl = BIO_new(BIO_s_mem()); if (into_ssl == NULL || from_ssl == NULL) { gpr_log(GPR_ERROR, "BIO_new failed."); SSL_free(ssl); if (into_ssl != NULL) BIO_free(into_ssl); if (from_ssl != NULL) BIO_free(into_ssl); return TSI_OUT_OF_RESOURCES; } SSL_set_bio(ssl, into_ssl, from_ssl); if (is_client) { int ssl_result; SSL_set_connect_state(ssl); if (server_name_indication != NULL) { if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) { gpr_log(GPR_ERROR, "Invalid server name indication %s.", server_name_indication); SSL_free(ssl); return TSI_INTERNAL_ERROR; } } ssl_result = SSL_do_handshake(ssl); ssl_result = SSL_get_error(ssl, ssl_result); if (ssl_result != SSL_ERROR_WANT_READ) { gpr_log(GPR_ERROR, "Unexpected error received from first SSL_do_handshake call: %s", ssl_error_string(ssl_result)); SSL_free(ssl); return TSI_INTERNAL_ERROR; } } else { SSL_set_accept_state(ssl); } impl = calloc(1, sizeof(tsi_ssl_handshaker)); if (impl == NULL) { SSL_free(ssl); return TSI_OUT_OF_RESOURCES; } impl->ssl = ssl; impl->into_ssl = into_ssl; impl->from_ssl = from_ssl; impl->result = TSI_HANDSHAKE_IN_PROGRESS; impl->base.vtable = &handshaker_vtable; *handshaker = &impl->base; return TSI_OK; } static int select_protocol_list(const unsigned char** out, unsigned char* outlen, const unsigned char* client_list, unsigned int client_list_len, const unsigned char* server_list, unsigned int server_list_len) { const unsigned char* client_current = client_list; while ((unsigned int)(client_current - client_list) < client_list_len) { unsigned char client_current_len = *(client_current++); const unsigned char* server_current = server_list; while ((server_current >= server_list) && (gpr_uintptr)(server_current - server_list) < server_list_len) { unsigned char server_current_len = *(server_current++); if ((client_current_len == server_current_len) && !memcmp(client_current, server_current, server_current_len)) { *out = server_current; *outlen = server_current_len; return SSL_TLSEXT_ERR_OK; } server_current += server_current_len; } client_current += client_current_len; } return SSL_TLSEXT_ERR_NOACK; } /* --- tsi_ssl__client_handshaker_factory methods implementation. --- */ static tsi_result ssl_client_handshaker_factory_create_handshaker( tsi_ssl_handshaker_factory* self, const char* server_name_indication, tsi_handshaker** handshaker) { tsi_ssl_client_handshaker_factory* impl = (tsi_ssl_client_handshaker_factory*)self; return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication, handshaker); } static void ssl_client_handshaker_factory_destroy( tsi_ssl_handshaker_factory* self) { tsi_ssl_client_handshaker_factory* impl = (tsi_ssl_client_handshaker_factory*)self; if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context); if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); free(impl); } static int client_handshaker_factory_npn_callback(SSL* ssl, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg) { tsi_ssl_client_handshaker_factory* factory = (tsi_ssl_client_handshaker_factory*)arg; return select_protocol_list((const unsigned char**)out, outlen, factory->alpn_protocol_list, factory->alpn_protocol_list_length, in, inlen); } /* --- tsi_ssl_server_handshaker_factory methods implementation. --- */ static tsi_result ssl_server_handshaker_factory_create_handshaker( tsi_ssl_handshaker_factory* self, const char* server_name_indication, tsi_handshaker** handshaker) { tsi_ssl_server_handshaker_factory* impl = (tsi_ssl_server_handshaker_factory*)self; if (impl->ssl_context_count == 0 || server_name_indication != NULL) { return TSI_INVALID_ARGUMENT; } /* Create the handshaker with the first context. We will switch if needed because of SNI in ssl_server_handshaker_factory_servername_callback. */ return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker); } static void ssl_server_handshaker_factory_destroy( tsi_ssl_handshaker_factory* self) { tsi_ssl_server_handshaker_factory* impl = (tsi_ssl_server_handshaker_factory*)self; size_t i; for (i = 0; i < impl->ssl_context_count; i++) { if (impl->ssl_contexts[i] != NULL) { SSL_CTX_free(impl->ssl_contexts[i]); tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]); } } if (impl->ssl_contexts != NULL) free(impl->ssl_contexts); if (impl->ssl_context_x509_subject_names != NULL) { free(impl->ssl_context_x509_subject_names); } if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); free(impl); } static int does_entry_match_name(const char* entry, size_t entry_length, const char* name) { const char* dot; const char* name_subdomain = NULL; size_t name_length = strlen(name); size_t name_subdomain_length; if (entry_length == 0) return 0; /* Take care of '.' terminations. */ if (name[name_length - 1] == '.') { name_length--; } if (entry[entry_length - 1] == '.') { entry_length--; if (entry_length == 0) return 0; } if ((name_length == entry_length) && strncmp(name, entry, entry_length) == 0) { return 1; /* Perfect match. */ } if (entry[0] != '*') return 0; /* Wildchar subdomain matching. */ if (entry_length < 3 || entry[1] != '.') { /* At least *.x */ gpr_log(GPR_ERROR, "Invalid wildchar entry."); return 0; } name_subdomain = strchr(name, '.'); if (name_subdomain == NULL) return 0; name_subdomain_length = strlen(name_subdomain); if (name_subdomain_length < 2) return 0; name_subdomain++; /* Starts after the dot. */ name_subdomain_length--; entry += 2; /* Remove *. */ entry_length -= 2; dot = strchr(name_subdomain, '.'); if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) { gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain); return 0; } if (name_subdomain[name_subdomain_length - 1] == '.') { name_subdomain_length--; } return ((entry_length > 0) && (name_subdomain_length == entry_length) && strncmp(entry, name_subdomain, entry_length) == 0); } static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap, void* arg) { tsi_ssl_server_handshaker_factory* impl = (tsi_ssl_server_handshaker_factory*)arg; size_t i = 0; const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername == NULL || strlen(servername) == 0) { return SSL_TLSEXT_ERR_NOACK; } for (i = 0; i < impl->ssl_context_count; i++) { if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i], servername)) { SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]); return SSL_TLSEXT_ERR_OK; } } gpr_log(GPR_ERROR, "No match found for server name: %s.", servername); return SSL_TLSEXT_ERR_ALERT_WARNING; } #if TSI_OPENSSL_ALPN_SUPPORT static int server_handshaker_factory_alpn_callback( SSL* ssl, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg) { tsi_ssl_server_handshaker_factory* factory = (tsi_ssl_server_handshaker_factory*)arg; return select_protocol_list(out, outlen, in, inlen, factory->alpn_protocol_list, factory->alpn_protocol_list_length); } #endif /* TSI_OPENSSL_ALPN_SUPPORT */ static int server_handshaker_factory_npn_advertised_callback( SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) { tsi_ssl_server_handshaker_factory* factory = (tsi_ssl_server_handshaker_factory*)arg; *out = factory->alpn_protocol_list; *outlen = factory->alpn_protocol_list_length; return SSL_TLSEXT_ERR_OK; } /* --- tsi_ssl_handshaker_factory constructors. --- */ tsi_result tsi_create_ssl_client_handshaker_factory( const unsigned char* pem_private_key, size_t pem_private_key_size, const unsigned char* pem_cert_chain, size_t pem_cert_chain_size, const unsigned char* pem_root_certs, size_t pem_root_certs_size, const char* cipher_list, const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, tsi_ssl_handshaker_factory** factory) { SSL_CTX* ssl_context = NULL; tsi_ssl_client_handshaker_factory* impl = NULL; tsi_result result = TSI_OK; gpr_once_init(&init_openssl_once, init_openssl); if (factory == NULL) return TSI_INVALID_ARGUMENT; *factory = NULL; if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT; ssl_context = SSL_CTX_new(TLSv1_2_method()); if (ssl_context == NULL) { gpr_log(GPR_ERROR, "Could not create ssl context."); return TSI_INVALID_ARGUMENT; } impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory)); if (impl == NULL) { SSL_CTX_free(ssl_context); return TSI_OUT_OF_RESOURCES; } impl->ssl_context = ssl_context; do { result = populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size, pem_cert_chain, pem_cert_chain_size, cipher_list); if (result != TSI_OK) break; result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs, pem_root_certs_size, NULL); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Cannot load server root certificates."); break; } if (num_alpn_protocols != 0) { result = build_alpn_protocol_name_list( alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Building alpn list failed with error %s.", tsi_result_to_string(result)); break; } #if TSI_OPENSSL_ALPN_SUPPORT if (SSL_CTX_set_alpn_protos(ssl_context, impl->alpn_protocol_list, impl->alpn_protocol_list_length)) { gpr_log(GPR_ERROR, "Could not set alpn protocol list to context."); result = TSI_INVALID_ARGUMENT; break; } #endif /* TSI_OPENSSL_ALPN_SUPPORT */ SSL_CTX_set_next_proto_select_cb( ssl_context, client_handshaker_factory_npn_callback, impl); } } while (0); if (result != TSI_OK) { ssl_client_handshaker_factory_destroy(&impl->base); return result; } SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL); /* TODO(jboeuf): Add revocation verification. */ impl->base.create_handshaker = ssl_client_handshaker_factory_create_handshaker; impl->base.destroy = ssl_client_handshaker_factory_destroy; *factory = &impl->base; return TSI_OK; } tsi_result tsi_create_ssl_server_handshaker_factory( const unsigned char** pem_private_keys, const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains, const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count, const unsigned char* pem_client_root_certs, size_t pem_client_root_certs_size, int force_client_auth, const char* cipher_list, const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, tsi_ssl_handshaker_factory** factory) { tsi_ssl_server_handshaker_factory* impl = NULL; tsi_result result = TSI_OK; size_t i = 0; gpr_once_init(&init_openssl_once, init_openssl); if (factory == NULL) return TSI_INVALID_ARGUMENT; *factory = NULL; if (key_cert_pair_count == 0 || pem_private_keys == NULL || pem_cert_chains == NULL) { return TSI_INVALID_ARGUMENT; } impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory)); if (impl == NULL) return TSI_OUT_OF_RESOURCES; impl->base.create_handshaker = ssl_server_handshaker_factory_create_handshaker; impl->base.destroy = ssl_server_handshaker_factory_destroy; impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX*)); impl->ssl_context_x509_subject_names = calloc(key_cert_pair_count, sizeof(tsi_peer)); if (impl->ssl_contexts == NULL || impl->ssl_context_x509_subject_names == NULL) { tsi_ssl_handshaker_factory_destroy(&impl->base); return TSI_OUT_OF_RESOURCES; } impl->ssl_context_count = key_cert_pair_count; if (num_alpn_protocols > 0) { result = build_alpn_protocol_name_list( alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); if (result != TSI_OK) { tsi_ssl_handshaker_factory_destroy(&impl->base); return result; } } for (i = 0; i < key_cert_pair_count; i++) { do { impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method()); if (impl->ssl_contexts[i] == NULL) { gpr_log(GPR_ERROR, "Could not create ssl context."); result = TSI_OUT_OF_RESOURCES; break; } result = populate_ssl_context( impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i], pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list); if (result != TSI_OK) break; if (pem_client_root_certs != NULL) { int flags = SSL_VERIFY_PEER; STACK_OF(X509_NAME)* root_names = NULL; result = ssl_ctx_load_verification_certs( impl->ssl_contexts[i], pem_client_root_certs, pem_client_root_certs_size, &root_names); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Invalid verification certs."); break; } SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names); if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL); /* TODO(jboeuf): Add revocation verification. */ } result = extract_x509_subject_names_from_pem_cert( pem_cert_chains[i], pem_cert_chains_sizes[i], &impl->ssl_context_x509_subject_names[i]); if (result != TSI_OK) break; SSL_CTX_set_tlsext_servername_callback( impl->ssl_contexts[i], ssl_server_handshaker_factory_servername_callback); SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl); #if TSI_OPENSSL_ALPN_SUPPORT SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i], server_handshaker_factory_alpn_callback, impl); #endif /* TSI_OPENSSL_ALPN_SUPPORT */ SSL_CTX_set_next_protos_advertised_cb( impl->ssl_contexts[i], server_handshaker_factory_npn_advertised_callback, impl); } while (0); if (result != TSI_OK) { tsi_ssl_handshaker_factory_destroy(&impl->base); return result; } } *factory = &impl->base; return TSI_OK; } /* --- tsi_ssl utils. --- */ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) { size_t i = 0; size_t san_count = 0; const tsi_peer_property* cn_property = NULL; /* For now reject what looks like an IP address. */ if (looks_like_ip_address(name)) return 0; /* Check the SAN first. */ for (i = 0; i < peer->property_count; i++) { const tsi_peer_property* property = &peer->properties[i]; if (property->name == NULL) continue; if (strcmp(property->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { san_count++; if (does_entry_match_name(property->value.data, property->value.length, name)) { return 1; } } else if (strcmp(property->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { cn_property = property; } } /* If there's no SAN, try the CN. */ if (san_count == 0 && cn_property != NULL) { if (does_entry_match_name(cn_property->value.data, cn_property->value.length, name)) { return 1; } } return 0; /* Not found. */ } grpc-0.11.1/src/core/tsi/transport_security.c0000644000175000017500000002361612600663151021374 0ustar apollockapollock/* * * 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/tsi/transport_security.h" #include #include /* --- Tracing. --- */ int tsi_tracing_enabled = 0; /* --- Utils. --- */ char* tsi_strdup(const char* src) { char* dst; size_t len; if (!src) return NULL; len = strlen(src) + 1; dst = malloc(len); if (!dst) return NULL; memcpy(dst, src, len); return dst; } /* --- tsi_result common implementation. --- */ const char* tsi_result_to_string(tsi_result result) { switch (result) { case TSI_OK: return "TSI_OK"; case TSI_UNKNOWN_ERROR: return "TSI_UNKNOWN_ERROR"; case TSI_INVALID_ARGUMENT: return "TSI_INVALID_ARGUMENT"; case TSI_PERMISSION_DENIED: return "TSI_PERMISSION_DENIED"; case TSI_INCOMPLETE_DATA: return "TSI_INCOMPLETE_DATA"; case TSI_FAILED_PRECONDITION: return "TSI_FAILED_PRECONDITION"; case TSI_UNIMPLEMENTED: return "TSI_UNIMPLEMENTED"; case TSI_INTERNAL_ERROR: return "TSI_INTERNAL_ERROR"; case TSI_DATA_CORRUPTED: return "TSI_DATA_CORRUPTED"; case TSI_NOT_FOUND: return "TSI_NOT_FOUND"; case TSI_PROTOCOL_FAILURE: return "TSI_PROTOCOL_FAILURE"; case TSI_HANDSHAKE_IN_PROGRESS: return "TSI_HANDSHAKE_IN_PROGRESS"; case TSI_OUT_OF_RESOURCES: return "TSI_OUT_OF_RESOURCES"; default: return "UNKNOWN"; } } /* --- tsi_frame_protector common implementation. --- Calls specific implementation after state/input validation. */ tsi_result tsi_frame_protector_protect(tsi_frame_protector* self, const unsigned char* unprotected_bytes, size_t* unprotected_bytes_size, unsigned char* protected_output_frames, size_t* protected_output_frames_size) { if (self == NULL || unprotected_bytes == NULL || unprotected_bytes_size == NULL || protected_output_frames == NULL || protected_output_frames_size == NULL) { return TSI_INVALID_ARGUMENT; } return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size, protected_output_frames, protected_output_frames_size); } tsi_result tsi_frame_protector_protect_flush( tsi_frame_protector* self, unsigned char* protected_output_frames, size_t* protected_output_frames_size, size_t* still_pending_size) { if (self == NULL || protected_output_frames == NULL || protected_output_frames == NULL || still_pending_size == NULL) { return TSI_INVALID_ARGUMENT; } return self->vtable->protect_flush(self, protected_output_frames, protected_output_frames_size, still_pending_size); } tsi_result tsi_frame_protector_unprotect( tsi_frame_protector* self, const unsigned char* protected_frames_bytes, size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, size_t* unprotected_bytes_size) { if (self == NULL || protected_frames_bytes == NULL || protected_frames_bytes_size == NULL || unprotected_bytes == NULL || unprotected_bytes_size == NULL) { return TSI_INVALID_ARGUMENT; } return self->vtable->unprotect(self, protected_frames_bytes, protected_frames_bytes_size, unprotected_bytes, unprotected_bytes_size); } void tsi_frame_protector_destroy(tsi_frame_protector* self) { if (self == NULL) return; self->vtable->destroy(self); } /* --- tsi_handshaker common implementation. --- Calls specific implementation after state/input validation. */ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self, unsigned char* bytes, size_t* bytes_size) { if (self == NULL) return TSI_INVALID_ARGUMENT; if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size); } tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) { if (self == NULL) return TSI_INVALID_ARGUMENT; if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; return self->vtable->process_bytes_from_peer(self, bytes, bytes_size); } tsi_result tsi_handshaker_get_result(tsi_handshaker* self) { if (self == NULL) return TSI_INVALID_ARGUMENT; if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; return self->vtable->get_result(self); } tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) { if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT; memset(peer, 0, sizeof(tsi_peer)); if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; if (tsi_handshaker_get_result(self) != TSI_OK) { return TSI_FAILED_PRECONDITION; } return self->vtable->extract_peer(self, peer); } tsi_result tsi_handshaker_create_frame_protector( tsi_handshaker* self, size_t* max_protected_frame_size, tsi_frame_protector** protector) { tsi_result result; if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT; if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; if (tsi_handshaker_get_result(self) != TSI_OK) { return TSI_FAILED_PRECONDITION; } result = self->vtable->create_frame_protector(self, max_protected_frame_size, protector); if (result == TSI_OK) { self->frame_protector_created = 1; } return result; } void tsi_handshaker_destroy(tsi_handshaker* self) { if (self == NULL) return; self->vtable->destroy(self); } /* --- tsi_peer implementation. --- */ tsi_peer_property tsi_init_peer_property(void) { tsi_peer_property property; memset(&property, 0, sizeof(tsi_peer_property)); return property; } static void tsi_peer_destroy_list_property(tsi_peer_property* children, size_t child_count) { size_t i; for (i = 0; i < child_count; i++) { tsi_peer_property_destruct(&children[i]); } free(children); } void tsi_peer_property_destruct(tsi_peer_property* property) { if (property->name != NULL) { free(property->name); } if (property->value.data != NULL) { free(property->value.data); } *property = tsi_init_peer_property(); /* Reset everything to 0. */ } void tsi_peer_destruct(tsi_peer* self) { if (self == NULL) return; if (self->properties != NULL) { tsi_peer_destroy_list_property(self->properties, self->property_count); self->properties = NULL; } self->property_count = 0; } tsi_result tsi_construct_allocated_string_peer_property( const char* name, size_t value_length, tsi_peer_property* property) { *property = tsi_init_peer_property(); if (name != NULL) { property->name = tsi_strdup(name); if (property->name == NULL) return TSI_OUT_OF_RESOURCES; } if (value_length > 0) { property->value.data = calloc(1, value_length); if (property->value.data == NULL) { tsi_peer_property_destruct(property); return TSI_OUT_OF_RESOURCES; } property->value.length = value_length; } return TSI_OK; } tsi_result tsi_construct_string_peer_property_from_cstring( const char* name, const char* value, tsi_peer_property* property) { return tsi_construct_string_peer_property(name, value, strlen(value), property); } tsi_result tsi_construct_string_peer_property(const char* name, const char* value, size_t value_length, tsi_peer_property* property) { tsi_result result = tsi_construct_allocated_string_peer_property( name, value_length, property); if (result != TSI_OK) return result; if (value_length > 0) { memcpy(property->value.data, value, value_length); } return TSI_OK; } tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer) { memset(peer, 0, sizeof(tsi_peer)); if (property_count > 0) { peer->properties = calloc(property_count, sizeof(tsi_peer_property)); if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES; peer->property_count = property_count; } return TSI_OK; } grpc-0.11.1/src/core/tsi/test_creds/0000755000175000017500000000000012600663151017374 5ustar apollockapollockgrpc-0.11.1/src/core/tsi/test_creds/ca.key0000644000175000017500000000162012600663151020470 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMBA3wVeTGHZR1Ry e/i+J8a2cu5gXwFV6TnObzGM7bLFCO5i9v4mLo4iFzPsHmWDUxKS3Y8iXbu0eYBl LoNY0lSvxDx33O+DuwMmVN+DzSD+Eod9zfvwOWHsazYCZT2PhNxnVWIuJXViY4JA HUGodjx+QAi6yCAurUZGvYXGgZSBAgMBAAECgYAxRi8i9BlFlufGSBVoGmydbJOm bwLKl9dP3o33ODSP9hok5y6A0w5plWk3AJSF1hPLleK9VcSKYGYnt0clmPVHF35g bx2rVK8dOT0mn7rz9Zr70jcSz1ETA2QonHZ+Y+niLmcic9At6hRtWiewblUmyFQm GwggIzi7LOyEUHrEcQJBAOXxyQvnLvtKzXiqcsW/K6rExqVJVk+KF0fzzVyMzTJx HRBxUVgvGdEJT7j+7P2kcTyafve0BBzDSPIaDyiJ+Y0CQQDWCb7jASFSbu5M3Zcd Gkr4ZKN1XO3VLQX10b22bQYdF45hrTN2tnzRvVUR4q86VVnXmiGiTqmLkXcA2WWf pHfFAkAhv9olUBo6MeF0i3frBEMRfm41hk0PwZHnMqZ6pgPcGnQMnMU2rzsXzkkQ OwJnvAIOxhJKovZTjmofdqmw5odlAkBYVUdRWjsNUTjJwj3GRf6gyq/nFMYWz3EB RWFdM1ttkDYzu45ctO2IhfHg4sPceDMO1s6AtKQmNI9/azkUjITdAkApNa9yFRzc TBaDNPd5KVd58LVIzoPQ6i7uMHteLXJUWqSroji6S3s4gKMFJ/dO+ZXIlgQgfJJJ ZDL4cdrdkeoM -----END PRIVATE KEY----- grpc-0.11.1/src/core/tsi/test_creds/badserver.key0000644000175000017500000000162412600663151022066 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKeZ1e1y29cmBKaW oIUwJ5neOJUjx+eD/3nRPe+dvLXEd9+db0fG5RYRR0S3mF1Ywuj4PIxlTW2YprUS oGSw+tcqWNIzxv94HjwYFkkvER3AblXcDBh0P2zAkzg+nf9AcAsMh0QpDTyrXtMl gqryjq1/vkhFofKMMbY+aXJdG6OBAgMBAAECgYAAgaB51S0A22aMMkxN2rVj6530 JWWHN4jgD1fGj41wZyWNkWYyq1Ep3ed/N6bIMWp1VbqpGe0/9YQba/D8HOTFHGRt 72YXnP1e/ds8cxU4x4j1vvqSPtXpMmkiXfXijOvCl9mrMH2xjghFAt6/1Nb9xo1m VdcOB8OdSuOIw6CI+QJBAN5FZUbS+bRXDWII/FaAih1DBpwCxhYEN+TXPJBxSen6 kOzGt5g+mB6YqRMZ/qshshwPq7bsgFGfJ2lIdS2t3GsCQQDBCKifV5AAkOdOUrkK HvoX3qnVmyIA8CyvWLcIWpfZ76QAYh0q0StedKdOMXaB1jTeSJ2KU1nlss7UD1Yw VbrDAkAwjMHpbW3jiVw//Kx5jIwehiRscWKpLnSzBJyTBFvbwsJjJai2lX2OuVO8 +2GYKb0Iyhd81j3VFkl6grwtpRtPAkB7+n+yt555fpfRKjhGU9b09cHGu7h/OcK5 bBVCfE0DYHLI/DsXgPiF1g6Onh4rDdUu3xyv9xDKAqnscV099hHZAkEAvcFBfXZs tk18N+bUcvXTdZjzZbfLCHlJmwPIspZ8G/6Pn63deg4GVYoCvTwGruah+8y734Ph 7PskfPgUQlB7Ag== -----END PRIVATE KEY----- grpc-0.11.1/src/core/tsi/test_creds/client.pem0000644000175000017500000000143612600663151021361 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcxNzIzNTYwMloXDTI0MDcxNDIzNTYw MlowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKdGVzdGNsaWVudDCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7FRH26G+Ft5VQgyzlZsfSnHSZ6GX b7qxmk2PO8TYqKZmkfMwke6RUfQV+S+GzRvz5LlS31U1QCp3cgwkIIAQa1E2hCEz W31ivbMByRK9tFpyn4Uv8KP14ObKjTQqxUZp558DgOHg5b5mGRM0pyV1eqRK6PWw R/bjglli6pmnr+0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAStSm5PM7ubROiKK6/ T2FkKlhiTOx+Ryenm3Eio59emq+jXl+1nhPySX5G2PQzSR5vd1dIhwgZSR4Gyttk tRZ57k/NI1brUW8joiEOMJA/Mr7H7asx7wIRYDE91Fs8GkKWd5LhoPAQj+qdG35C OO+svdkmqH0KZo320ZUqdl2ooQ== -----END CERTIFICATE----- grpc-0.11.1/src/core/tsi/test_creds/badserver.pem0000644000175000017500000000171512600663151022060 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICoDCCAgmgAwIBAgIJAPdqwqsKNy81MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZHNlcnZlci50ZXN0Lmdvb2dsZS5j b20wHhcNMTQwNzI4MjAwODU0WhcNMjQwNzI1MjAwODU0WjBpMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRzZXJ2ZXIudGVzdC5nb29nbGUuY29tMIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnmdXtctvXJgSmlqCFMCeZ3jiVI8fn g/950T3vnby1xHffnW9HxuUWEUdEt5hdWMLo+DyMZU1tmKa1EqBksPrXKljSM8b/ eB48GBZJLxEdwG5V3AwYdD9swJM4Pp3/QHALDIdEKQ08q17TJYKq8o6tf75IRaHy jDG2PmlyXRujgQIDAQABo1AwTjAdBgNVHQ4EFgQU3u/qvHr9knMBeZyAD7mAA/ec 8cUwHwYDVR0jBBgwFoAU3u/qvHr9knMBeZyAD7mAA/ec8cUwDAYDVR0TBAUwAwEB /zANBgkqhkiG9w0BAQUFAAOBgQA/FmR1SGLguxCCfhp4CYCbrAePSyPWDi48gTwj vVZf/OMxdVu/H8sBYFf27BjbrEugAw16DElFtgTZ83pLb2BvkUgb6vBUK5sEkgmh z88zBsgDp8aCf4STDOLFZMBh/E9ZKkm1zogbEmlTjFp/ceSpa2gNv7OuN4WiorOh Wvw40g== -----END CERTIFICATE----- grpc-0.11.1/src/core/tsi/test_creds/server1-openssl.cnf0000644000175000017500000000142612600663151023137 0ustar apollockapollock[req] distinguished_name = req_distinguished_name req_extensions = v3_req [req_distinguished_name] countryName = Country Name (2 letter code) countryName_default = US stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Illinois localityName = Locality Name (eg, city) localityName_default = Chicago organizationName = Organization Name (eg, company) organizationName_default = Example, Co. commonName = Common Name (eg, YOUR name) commonName_max = 64 [v3_req] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = *.test.google.fr DNS.2 = waterzooi.test.google.be DNS.3 = *.test.youtube.com IP.1 = "192.168.1.3" grpc-0.11.1/src/core/tsi/test_creds/server1.pem0000644000175000017500000000170412600663151021470 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= -----END CERTIFICATE----- grpc-0.11.1/src/core/tsi/test_creds/ca.pem0000644000175000017500000000152712600663151020467 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 +L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG Dfcog5wrJytaQ6UA0wE= -----END CERTIFICATE----- grpc-0.11.1/src/core/tsi/test_creds/badclient.key0000644000175000017500000000162412600663151022036 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALJfYnFn4nkj52WF E5W2qUxCfjsEFyuXYYKS/07UPWsv3gpZhtjXgdeGL+dpwEBC0IRDBfGnkMp6YY5S O7rnEz0X3r/fvgYy+dEl2jnaA6zgc7RzMGl9U11d56gP9FiDC2190mvP/hpq2xLZ CTbIximpmaoQyxuuH1bbYunesIG/AgMBAAECgYAdqJCEzMIyZE7oaW0tOpcB0BiP FYoIvH4BKRH8eHvR476mt+YdDhBP1scGUmYeCT4Ej+RgHv2LPTgVYwT9eciP2+E/ CBCNRel0Sw9JepwW0r+jWJtDY1pp6YXAgNRGX2UflvUsT+o9lZvagf9moLTMyGvU uLFnsyfLim1B4vXvWQJBANouZllXGZoSrZLtR3VgV4tzRQvJxu84kLeIk64Ov47X pHVBMTRBfzPEhbBodjr1m5OLaVLqkFcXftzRCrbWoKsCQQDRSoLLXOiLrtJ3DLJC rX7Y8wrHZrqk5bMdZLGa/UX8RanhVw3+Xp+urd1711umeNJfzu/MCk4a1KkG/CU0 rqs9AkA4cSx1DD1JSG+yxMNpsAS1xJomFIrsM9vsPt7FdndDwrF+y+CovhDkGYDk RAHh+svGfZg/pQK2JRPimAmHhzqFAkEAu6Ya70s2FUeB3Mu9aJs2CD6hg3dQEVkB 53DI7TX48d9kGW58VX1xnqS02LyWqAPcW5qm1kLHFLdndaPNmBaj4QJBAJugl367 9d9t/QLTSuULLaoYv2vJT3s1y9HN89EoaDDEkPVfQu6GVEXgIBtim1sI/VPSzI8H aXvaTUwblFWSM70= -----END PRIVATE KEY----- grpc-0.11.1/src/core/tsi/test_creds/README0000644000175000017500000000403112600663151020252 0ustar apollockapollockThe test credentials (CONFIRMEDTESTKEY) have been generated with the following commands: Bad credentials (badclient.* / badserver.*): ============================================ These are self-signed certificates: $ openssl req -x509 -newkey rsa:1024 -keyout badserver.key -out badserver.pem \ -days 3650 -nodes When prompted for certificate information, everything is default except the common name which is set to badserver.test.google.com. Valid test credentials: ======================= The ca is self-signed: ---------------------- $ openssl req -x509 -new -newkey rsa:1024 -nodes -out ca.pem -config ca-openssl.cnf -days 3650 -extensions v3_req When prompted for certificate information, everything is default. client is issued by CA: ----------------------- $ openssl genrsa -out client.key.rsa 1024 $ openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt $ rm client.key.rsa $ openssl req -new -key client.key -out client.csr When prompted for certificate information, everything is default except the common name which is set to testclient. $ openssl ca -in client.csr -out client.pem server0 is issued by CA: ------------------------ $ openssl genrsa -out server0.key.rsa 1024 $ openssl pkcs8 -topk8 -in server0.key.rsa -out server0.key -nocrypt $ rm server0.key.rsa $ openssl req -new -key server0.key -out server0.csr When prompted for certificate information, everything is default except the common name which is set to *.test.google.com.au. $ openssl ca -in server0.csr -out server0.pem server1 is issued by CA with a special config for subject alternative names: ---------------------------------------------------------------------------- $ openssl genrsa -out server1.key.rsa 1024 $ openssl pkcs8 -topk8 -in server1.key.rsa -out server1.key -nocrypt $ rm server1.key.rsa $ openssl req -new -key server1.key -out server1.csr -config server1-openssl.cnf When prompted for certificate information, everything is default except the common name which is set to *.test.google.com. $ openssl ca -in server1.csr -out server1.pem grpc-0.11.1/src/core/tsi/test_creds/server0.key0000644000175000017500000000162412600663151021477 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOmffupIGC8YDau rOF4eKnHwPszgpkkhWzKsVxhNDBxCVYx4TEjG0XWIO0iyRXupZbUC+7N/8HnEVNa 8F1jYhng14Iiq99cNQbbnuHHhIztmpocrJTxmnhGzoAnRa1Tb+GnAuRoIHRA/V2c VUE9tbikQugFx/SPgXAw6tfWB+YvAgMBAAECgYEAoEq9qzUBgoHoVEGiSPiWWe8g 5p6yUA1qx2QTQyWTAwT4z0DjjfVKmG99bFsl8+hTnJFnoCp/gnjflEOROwkjp5kG m0drqOPx1jeipJjpXYTBu49h+WpZ1PF+KhVtxsIm3OOCvh67iWaKyyOVb5Og8aiR jl6dn/TdG/dlGD8AfUECQQDuNMle6p0oU8amC6O9wIMBroxx2nFstzE6O35PLEzG /tj0kxxn9Jp2TS9mGaLCzSuXmpjlF4+NOWiBPkrLC2TfAkEA43Xg7uEUkaJAz2/W m1lIBTLt+4rIQY/2emh33bDcA+rv8rwwrMMIv17/xPx7bs49YqGG5xufD+Rwl6TL qFXYsQJAPrOwagax1aKvwJeBw3oAQhoTKAkLIEXcdGqipe6QSzVcIIz0xjxxyEAr AOIwoLxnBCISqwMXq2H4K0UdZPMb2wJAdhdYLY1L6YRMk6XjzImg25oidisKZweA FvMv8DgHMj2CUAqmVrt3SivfLH1M9C09L3zfFhOAFHcsgX58gav4MQJBANSBnrHj tIq4l8z79CPUIuu3QyeEh+XwY8s5qE5CNTck0U59lzp9NvENHbkx3KO896TTerko +8bXHMLkJkHPXms= -----END PRIVATE KEY----- grpc-0.11.1/src/core/tsi/test_creds/server0.pem0000644000175000017500000000143212600663151021465 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICHDCCAYUCAQQwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcyMjE3NTk0OVoXDTI0MDcxOTE3NTk0 OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFDASBgNVBAoM C0dvb2dsZSBJbmMuMR0wGwYDVQQDDBQqLnRlc3QuZ29vZ2xlLmNvbS5hdTCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06Z9+6kgYLxgNq6s4Xh4qcfA+zOCmSSF bMqxXGE0MHEJVjHhMSMbRdYg7SLJFe6lltQL7s3/wecRU1rwXWNiGeDXgiKr31w1 Btue4ceEjO2amhyslPGaeEbOgCdFrVNv4acC5GggdED9XZxVQT21uKRC6AXH9I+B cDDq19YH5i8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBtfR5qXG9TTI8YcYh7sA4V GeNoplp0x6p7OG0NLvbJqAkUnkvjIkk1m1R2AUHhbkxzx6G75JIOoNJcWrCzywBA BIsaTdmnNysf/s1hQJuD3IHiVb+7Ji0jhttnJlYcMid4o0tJO/a2E9YUxR+9cg0i obb+Ql3qsvKdWBC1dDLDLw== -----END CERTIFICATE----- grpc-0.11.1/src/core/tsi/test_creds/badclient.pem0000644000175000017500000000171512600663151022030 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICoDCCAgmgAwIBAgIJANIz2/zoRiapMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZGNsaWVudC50ZXN0Lmdvb2dsZS5j b20wHhcNMTQwNzI4MjAwODI1WhcNMjQwNzI1MjAwODI1WjBpMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRjbGllbnQudGVzdC5nb29nbGUuY29tMIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyX2JxZ+J5I+dlhROVtqlMQn47BBcr l2GCkv9O1D1rL94KWYbY14HXhi/nacBAQtCEQwXxp5DKemGOUju65xM9F96/374G MvnRJdo52gOs4HO0czBpfVNdXeeoD/RYgwttfdJrz/4aatsS2Qk2yMYpqZmqEMsb rh9W22Lp3rCBvwIDAQABo1AwTjAdBgNVHQ4EFgQU523AJMR8Ds9V8fhf7gu1i0MM UqAwHwYDVR0jBBgwFoAU523AJMR8Ds9V8fhf7gu1i0MMUqAwDAYDVR0TBAUwAwEB /zANBgkqhkiG9w0BAQUFAAOBgQCI/tvSBYH1iyfLaCTBKwpdj36+MkR9EeJJmImx X+bjhKWXwsBX4PDMWvdusr++QGUYtyoya+hfYMXRhXua39mD54xgloQNuu9REDwX Ffto+aOw3BcYducz6ofxicFK/Y2VeXDurSMpRv5TfGf2Qr6eOOdaRhj6ed7BibHk X1VGZA== -----END CERTIFICATE----- grpc-0.11.1/src/core/tsi/test_creds/client.key0000644000175000017500000000163012600663151021364 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH 0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5 0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5 /sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/ U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP 1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd 9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI JiqOszq9GWESErAatg== -----END PRIVATE KEY----- grpc-0.11.1/src/core/tsi/test_creds/server1.key0000644000175000017500000000162012600663151021474 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf 3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR 81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe F98XJ7tIFfJq -----END PRIVATE KEY----- grpc-0.11.1/src/core/tsi/test_creds/ca-openssl.cnf0000644000175000017500000000103512600663151022127 0ustar apollockapollock[req] distinguished_name = req_distinguished_name req_extensions = v3_req [req_distinguished_name] countryName = Country Name (2 letter code) countryName_default = AU stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Some-State organizationName = Organization Name (eg, company) organizationName_default = Internet Widgits Pty Ltd commonName = Common Name (eg, YOUR name) commonName_default = testca [v3_req] basicConstraints = CA:true keyUsage = critical, keyCertSign grpc-0.11.1/src/core/tsi/fake_transport_security.c0000644000175000017500000004601712600663151022362 0ustar apollockapollock/* * * 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/tsi/fake_transport_security.h" #include #include #include #include #include #include "src/core/tsi/transport_security.h" /* --- Constants. ---*/ #define TSI_FAKE_FRAME_HEADER_SIZE 4 #define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64 #define TSI_FAKE_DEFAULT_FRAME_SIZE 16384 /* --- Structure definitions. ---*/ /* a frame is encoded like this: | size | data | where the size field value is the size of the size field plus the size of the data encoded in little endian on 4 bytes. */ typedef struct { unsigned char* data; size_t size; size_t allocated_size; size_t offset; int needs_draining; } tsi_fake_frame; typedef enum { TSI_FAKE_CLIENT_INIT = 0, TSI_FAKE_SERVER_INIT = 1, TSI_FAKE_CLIENT_FINISHED = 2, TSI_FAKE_SERVER_FINISHED = 3, TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4 } tsi_fake_handshake_message; typedef struct { tsi_handshaker base; int is_client; tsi_fake_handshake_message next_message_to_send; int needs_incoming_message; tsi_fake_frame incoming; tsi_fake_frame outgoing; tsi_result result; } tsi_fake_handshaker; typedef struct { tsi_frame_protector base; tsi_fake_frame protect_frame; tsi_fake_frame unprotect_frame; size_t max_frame_size; } tsi_fake_frame_protector; /* --- Utils. ---*/ static const char* tsi_fake_handshake_message_strings[] = { "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"}; static const char* tsi_fake_handshake_message_to_string(int msg) { if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { gpr_log(GPR_ERROR, "Invalid message %d", msg); return "UNKNOWN"; } return tsi_fake_handshake_message_strings[msg]; } static tsi_result tsi_fake_handshake_message_from_string( const char* msg_string, tsi_fake_handshake_message* msg) { int i; for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) { if (strncmp(msg_string, tsi_fake_handshake_message_strings[i], strlen(tsi_fake_handshake_message_strings[i])) == 0) { *msg = i; return TSI_OK; } } gpr_log(GPR_ERROR, "Invalid handshake message."); return TSI_DATA_CORRUPTED; } static gpr_uint32 load32_little_endian(const unsigned char* buf) { return ((gpr_uint32)(buf[0]) | (gpr_uint32)(buf[1] << 8) | (gpr_uint32)(buf[2] << 16) | (gpr_uint32)(buf[3] << 24)); } static void store32_little_endian(gpr_uint32 value, unsigned char* buf) { buf[3] = (unsigned char)(value >> 24) & 0xFF; buf[2] = (unsigned char)(value >> 16) & 0xFF; buf[1] = (unsigned char)(value >> 8) & 0xFF; buf[0] = (unsigned char)(value)&0xFF; } static void tsi_fake_frame_reset(tsi_fake_frame* frame, int needs_draining) { frame->offset = 0; frame->needs_draining = needs_draining; if (!needs_draining) frame->size = 0; } /* Returns 1 if successful, 0 otherwise. */ static int tsi_fake_frame_ensure_size(tsi_fake_frame* frame) { if (frame->data == NULL) { frame->allocated_size = frame->size; frame->data = malloc(frame->allocated_size); if (frame->data == NULL) return 0; } else if (frame->size > frame->allocated_size) { unsigned char* new_data = realloc(frame->data, frame->size); if (new_data == NULL) { free(frame->data); frame->data = NULL; return 0; } frame->data = new_data; frame->allocated_size = frame->size; } return 1; } /* This method should not be called if frame->needs_framing is not 0. */ static tsi_result fill_frame_from_bytes(const unsigned char* incoming_bytes, size_t* incoming_bytes_size, tsi_fake_frame* frame) { size_t available_size = *incoming_bytes_size; size_t to_read_size = 0; const unsigned char* bytes_cursor = incoming_bytes; if (frame->needs_draining) return TSI_INTERNAL_ERROR; if (frame->data == NULL) { frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE; frame->data = malloc(frame->allocated_size); if (frame->data == NULL) return TSI_OUT_OF_RESOURCES; } if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) { to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset; if (to_read_size > available_size) { /* Just fill what we can and exit. */ memcpy(frame->data + frame->offset, bytes_cursor, available_size); bytes_cursor += available_size; frame->offset += available_size; *incoming_bytes_size = bytes_cursor - incoming_bytes; return TSI_INCOMPLETE_DATA; } memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); bytes_cursor += to_read_size; frame->offset += to_read_size; available_size -= to_read_size; frame->size = load32_little_endian(frame->data); if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; } to_read_size = frame->size - frame->offset; if (to_read_size > available_size) { memcpy(frame->data + frame->offset, bytes_cursor, available_size); frame->offset += available_size; bytes_cursor += available_size; *incoming_bytes_size = bytes_cursor - incoming_bytes; return TSI_INCOMPLETE_DATA; } memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); bytes_cursor += to_read_size; *incoming_bytes_size = bytes_cursor - incoming_bytes; tsi_fake_frame_reset(frame, 1 /* needs_draining */); return TSI_OK; } /* This method should not be called if frame->needs_framing is 0. */ static tsi_result drain_frame_to_bytes(unsigned char* outgoing_bytes, size_t* outgoing_bytes_size, tsi_fake_frame* frame) { size_t to_write_size = frame->size - frame->offset; if (!frame->needs_draining) return TSI_INTERNAL_ERROR; if (*outgoing_bytes_size < to_write_size) { memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size); frame->offset += *outgoing_bytes_size; return TSI_INCOMPLETE_DATA; } memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size); *outgoing_bytes_size = to_write_size; tsi_fake_frame_reset(frame, 0 /* needs_draining */); return TSI_OK; } static tsi_result bytes_to_frame(unsigned char* bytes, size_t bytes_size, tsi_fake_frame* frame) { frame->offset = 0; frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE; if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; store32_little_endian(frame->size, frame->data); memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size); tsi_fake_frame_reset(frame, 1 /* needs draining */); return TSI_OK; } static void tsi_fake_frame_destruct(tsi_fake_frame* frame) { if (frame->data != NULL) free(frame->data); } /* --- tsi_frame_protector methods implementation. ---*/ static tsi_result fake_protector_protect(tsi_frame_protector* self, const unsigned char* unprotected_bytes, size_t* unprotected_bytes_size, unsigned char* protected_output_frames, size_t* protected_output_frames_size) { tsi_result result = TSI_OK; tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self; unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE]; tsi_fake_frame* frame = &impl->protect_frame; size_t saved_output_size = *protected_output_frames_size; size_t drained_size = 0; size_t* num_bytes_written = protected_output_frames_size; *num_bytes_written = 0; /* Try to drain first. */ if (frame->needs_draining) { drained_size = saved_output_size - *num_bytes_written; result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame); *num_bytes_written += drained_size; protected_output_frames += drained_size; if (result != TSI_OK) { if (result == TSI_INCOMPLETE_DATA) { *unprotected_bytes_size = 0; result = TSI_OK; } return result; } } /* Now process the unprotected_bytes. */ if (frame->needs_draining) return TSI_INTERNAL_ERROR; if (frame->size == 0) { /* New frame, create a header. */ size_t written_in_frame_size = 0; store32_little_endian(impl->max_frame_size, frame_header); written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE; result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame); if (result != TSI_INCOMPLETE_DATA) { gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s", tsi_result_to_string(result)); return result; } } result = fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame); if (result != TSI_OK) { if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; } /* Try to drain again. */ if (!frame->needs_draining) return TSI_INTERNAL_ERROR; if (frame->offset != 0) return TSI_INTERNAL_ERROR; drained_size = saved_output_size - *num_bytes_written; result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame); *num_bytes_written += drained_size; if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; } static tsi_result fake_protector_protect_flush( tsi_frame_protector* self, unsigned char* protected_output_frames, size_t* protected_output_frames_size, size_t* still_pending_size) { tsi_result result = TSI_OK; tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self; tsi_fake_frame* frame = &impl->protect_frame; if (!frame->needs_draining) { /* Create a short frame. */ frame->size = frame->offset; frame->offset = 0; frame->needs_draining = 1; store32_little_endian(frame->size, frame->data); /* Overwrite header. */ } result = drain_frame_to_bytes(protected_output_frames, protected_output_frames_size, frame); if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; *still_pending_size = frame->size - frame->offset; return result; } static tsi_result fake_protector_unprotect( tsi_frame_protector* self, const unsigned char* protected_frames_bytes, size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, size_t* unprotected_bytes_size) { tsi_result result = TSI_OK; tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self; tsi_fake_frame* frame = &impl->unprotect_frame; size_t saved_output_size = *unprotected_bytes_size; size_t drained_size = 0; size_t* num_bytes_written = unprotected_bytes_size; *num_bytes_written = 0; /* Try to drain first. */ if (frame->needs_draining) { /* Go past the header if needed. */ if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; drained_size = saved_output_size - *num_bytes_written; result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); unprotected_bytes += drained_size; *num_bytes_written += drained_size; if (result != TSI_OK) { if (result == TSI_INCOMPLETE_DATA) { *protected_frames_bytes_size = 0; result = TSI_OK; } return result; } } /* Now process the protected_bytes. */ if (frame->needs_draining) return TSI_INTERNAL_ERROR; result = fill_frame_from_bytes(protected_frames_bytes, protected_frames_bytes_size, frame); if (result != TSI_OK) { if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; } /* Try to drain again. */ if (!frame->needs_draining) return TSI_INTERNAL_ERROR; if (frame->offset != 0) return TSI_INTERNAL_ERROR; frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */ drained_size = saved_output_size - *num_bytes_written; result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); *num_bytes_written += drained_size; if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; } static void fake_protector_destroy(tsi_frame_protector* self) { tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self; tsi_fake_frame_destruct(&impl->protect_frame); tsi_fake_frame_destruct(&impl->unprotect_frame); free(self); } static const tsi_frame_protector_vtable frame_protector_vtable = { fake_protector_protect, fake_protector_protect_flush, fake_protector_unprotect, fake_protector_destroy, }; /* --- tsi_handshaker methods implementation. ---*/ static tsi_result fake_handshaker_get_bytes_to_send_to_peer( tsi_handshaker* self, unsigned char* bytes, size_t* bytes_size) { tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self; tsi_result result = TSI_OK; if (impl->needs_incoming_message || impl->result == TSI_OK) { *bytes_size = 0; return TSI_OK; } if (!impl->outgoing.needs_draining) { int next_message_to_send = impl->next_message_to_send + 2; const char* msg_string = tsi_fake_handshake_message_to_string(impl->next_message_to_send); result = bytes_to_frame((unsigned char*)msg_string, strlen(msg_string), &impl->outgoing); if (result != TSI_OK) return result; if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; } if (tsi_tracing_enabled) { gpr_log(GPR_INFO, "%s prepared %s.", impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(impl->next_message_to_send)); } impl->next_message_to_send = next_message_to_send; } result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing); if (result != TSI_OK) return result; if (!impl->is_client && impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { /* We're done. */ if (tsi_tracing_enabled) { gpr_log(GPR_INFO, "Server is done."); } impl->result = TSI_OK; } else { impl->needs_incoming_message = 1; } return TSI_OK; } static tsi_result fake_handshaker_process_bytes_from_peer( tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) { tsi_result result = TSI_OK; tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self; tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1; tsi_fake_handshake_message received_msg; if (!impl->needs_incoming_message || impl->result == TSI_OK) { *bytes_size = 0; return TSI_OK; } result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming); if (result != TSI_OK) return result; /* We now have a complete frame. */ result = tsi_fake_handshake_message_from_string( (const char*)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE, &received_msg); if (result != TSI_OK) { impl->result = result; return result; } if (received_msg != expected_msg) { gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)", tsi_fake_handshake_message_to_string(received_msg), tsi_fake_handshake_message_to_string(expected_msg)); } if (tsi_tracing_enabled) { gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(received_msg)); } tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */); impl->needs_incoming_message = 0; if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { /* We're done. */ if (tsi_tracing_enabled) { gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server"); } impl->result = TSI_OK; } return TSI_OK; } static tsi_result fake_handshaker_get_result(tsi_handshaker* self) { tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self; return impl->result; } static tsi_result fake_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) { tsi_result result = tsi_construct_peer(1, peer); if (result != TSI_OK) return result; result = tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, &peer->properties[0]); if (result != TSI_OK) tsi_peer_destruct(peer); return result; } static tsi_result fake_handshaker_create_frame_protector( tsi_handshaker* self, size_t* max_protected_frame_size, tsi_frame_protector** protector) { *protector = tsi_create_fake_protector(max_protected_frame_size); if (*protector == NULL) return TSI_OUT_OF_RESOURCES; return TSI_OK; } static void fake_handshaker_destroy(tsi_handshaker* self) { tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self; tsi_fake_frame_destruct(&impl->incoming); tsi_fake_frame_destruct(&impl->outgoing); free(self); } static const tsi_handshaker_vtable handshaker_vtable = { fake_handshaker_get_bytes_to_send_to_peer, fake_handshaker_process_bytes_from_peer, fake_handshaker_get_result, fake_handshaker_extract_peer, fake_handshaker_create_frame_protector, fake_handshaker_destroy, }; tsi_handshaker* tsi_create_fake_handshaker(int is_client) { tsi_fake_handshaker* impl = calloc(1, sizeof(tsi_fake_handshaker)); impl->base.vtable = &handshaker_vtable; impl->is_client = is_client; impl->result = TSI_HANDSHAKE_IN_PROGRESS; if (is_client) { impl->needs_incoming_message = 0; impl->next_message_to_send = TSI_FAKE_CLIENT_INIT; } else { impl->needs_incoming_message = 1; impl->next_message_to_send = TSI_FAKE_SERVER_INIT; } return &impl->base; } tsi_frame_protector* tsi_create_fake_protector( size_t* max_protected_frame_size) { tsi_fake_frame_protector* impl = calloc(1, sizeof(tsi_fake_frame_protector)); if (impl == NULL) return NULL; impl->max_frame_size = (max_protected_frame_size == NULL) ? TSI_FAKE_DEFAULT_FRAME_SIZE : *max_protected_frame_size; impl->base.vtable = &frame_protector_vtable; return &impl->base; } grpc-0.11.1/src/core/tsi/ssl_transport_security.h0000644000175000017500000002116512600663151022257 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H #define GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H #include "src/core/tsi/transport_security_interface.h" #ifdef __cplusplus extern "C" { #endif /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */ #define TSI_X509_CERTIFICATE_TYPE "X509" /* This property is of type TSI_PEER_PROPERTY_STRING. */ #define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name" #define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \ "x509_subject_alternative_name" #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" /* --- tsi_ssl_handshaker_factory object --- This object creates tsi_handshaker objects implemented in terms of the TLS 1.2 specificiation. */ typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory; /* Creates a client handshaker factory. - pem_private_key is the buffer containing the PEM encoding of the client's private key. This parameter can be NULL if the client does not have a private key. - pem_private_key_size is the size of the associated buffer. - pem_cert_chain is the buffer containing the PEM encoding of the client's certificate chain. This parameter can be NULL if the client does not have a certificate chain. - pem_cert_chain_size is the size of the associated buffer. - pem_roots_cert is the buffer containing the PEM encoding of the server root certificates. This parameter cannot be NULL. - pem_roots_cert_size is the size of the associated buffer. - cipher_suites contains an optional list of the ciphers that the client supports. The format of this string is described in: https://www.openssl.org/docs/apps/ciphers.html. This parameter can be set to NULL to use the default set of ciphers. TODO(jboeuf): Revisit the format of this parameter. - alpn_protocols is an array containing the protocol names that the handshakers created with this factory support. This parameter can be NULL. - alpn_protocols_lengths is an array containing the lengths of the alpn protocols specified in alpn_protocols. This parameter can be NULL. - num_alpn_protocols is the number of alpn protocols and associated lengths specified. If this parameter is 0, the other alpn parameters must be NULL. - factory is the address of the factory pointer to be created. - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case where a parameter is invalid. */ tsi_result tsi_create_ssl_client_handshaker_factory( const unsigned char* pem_private_key, size_t pem_private_key_size, const unsigned char* pem_cert_chain, size_t pem_cert_chain_size, const unsigned char* pem_root_certs, size_t pem_root_certs_size, const char* cipher_suites, const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, tsi_ssl_handshaker_factory** factory); /* Creates a server handshaker factory. - version indicates which version of the specification to use. - pem_private_keys is an array containing the PEM encoding of the server's private keys. This parameter cannot be NULL. The size of the array is given by the key_cert_pair_count parameter. - pem_private_keys_sizes is the array containing the sizes of the associated buffers. - pem_cert_chains is an array containing the PEM encoding of the server's cert chains. This parameter cannot be NULL. The size of the array is given by the key_cert_pair_count parameter. - pem_cert_chains_sizes is the array containing the sizes of the associated buffers. - key_cert_pair_count indicates the number of items in the private_key_files and cert_chain_files parameters. - pem_client_roots is the buffer containing the PEM encoding of the client root certificates. This parameter may be NULL in which case the server will not authenticate the client. If not NULL, the force_client_auth parameter specifies if the server will accept only authenticated clients or both authenticated and non-authenticated clients. - pem_client_root_certs_size is the size of the associated buffer. - force_client_auth, if set to non-zero will force the client to authenticate with an SSL cert. Note that this option is ignored if pem_client_root_certs is NULL or pem_client_roots_certs_size is 0 - cipher_suites contains an optional list of the ciphers that the server supports. The format of this string is described in: https://www.openssl.org/docs/apps/ciphers.html. This parameter can be set to NULL to use the default set of ciphers. TODO(jboeuf): Revisit the format of this parameter. - alpn_protocols is an array containing the protocol names that the handshakers created with this factory support. This parameter can be NULL. - alpn_protocols_lengths is an array containing the lengths of the alpn protocols specified in alpn_protocols. This parameter can be NULL. - num_alpn_protocols is the number of alpn protocols and associated lengths specified. If this parameter is 0, the other alpn parameters must be NULL. - factory is the address of the factory pointer to be created. - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case where a parameter is invalid. */ tsi_result tsi_create_ssl_server_handshaker_factory( const unsigned char** pem_private_keys, const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains, const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count, const unsigned char* pem_client_root_certs, size_t pem_client_root_certs_size, int force_client_auth, const char* cipher_suites, const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, tsi_ssl_handshaker_factory** factory); /* Creates a handshaker. - self is the factory from which the handshaker will be created. - server_name_indication indicates the name of the server the client is trying to connect to which will be relayed to the server using the SNI extension. This parameter must be NULL for a server handshaker factory. - handhshaker is the address of the handshaker pointer to be created. - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case where a parameter is invalid. */ tsi_result tsi_ssl_handshaker_factory_create_handshaker( tsi_ssl_handshaker_factory* self, const char* server_name_indication, tsi_handshaker** handshaker); /* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory while handshakers created with this factory are still in use. */ void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self); /* Util that checks that an ssl peer matches a specific name. Still TODO(jboeuf): - handle mixed case. - handle %encoded chars. - handle public suffix wildchar more strictly (e.g. *.co.uk) - handle IP addresses in SAN. */ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H */ grpc-0.11.1/src/core/tsi/transport_security_interface.h0000644000175000017500000003542612600663151023423 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H #define GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H #include #include #ifdef __cplusplus extern "C" { #endif /* --- tsi result --- */ typedef enum { TSI_OK = 0, TSI_UNKNOWN_ERROR = 1, TSI_INVALID_ARGUMENT = 2, TSI_PERMISSION_DENIED = 3, TSI_INCOMPLETE_DATA = 4, TSI_FAILED_PRECONDITION = 5, TSI_UNIMPLEMENTED = 6, TSI_INTERNAL_ERROR = 7, TSI_DATA_CORRUPTED = 8, TSI_NOT_FOUND = 9, TSI_PROTOCOL_FAILURE = 10, TSI_HANDSHAKE_IN_PROGRESS = 11, TSI_OUT_OF_RESOURCES = 12 } tsi_result; const char* tsi_result_to_string(tsi_result result); /* --- tsi tracing --- */ /* Set this early to avoid races */ extern int tsi_tracing_enabled; /* --- tsi_frame_protector object --- This object protects and unprotects buffers once the handshake is done. Implementations of this object must be thread compatible. */ typedef struct tsi_frame_protector tsi_frame_protector; /* Outputs protected frames. - unprotected_bytes is an input only parameter and points to the data to be protected. - unprotected_bytes_size is an input/output parameter used by the caller to specify how many bytes are available in unprotected_bytes. The output value is the number of bytes consumed during the call. - protected_output_frames points to a buffer allocated by the caller that will be written. - protected_output_frames_size is an input/output parameter used by the caller to specify how many bytes are available in protected_output_frames. As an output, this value indicates the number of bytes written. - This method returns TSI_OK in case of success or a specific error code in case of failure. Note that even if all the input unprotected bytes are consumed, they may not have been processed into the returned protected output frames. The caller should call the protect_flush method to make sure that there are no more protected bytes buffered in the protector. A typical way to call this method would be: ------------------------------------------------------------------------ unsigned char protected_buffer[4096]; size_t protected_buffer_size = sizeof(protected_buffer); tsi_result result = TSI_OK; while (message_size > 0) { size_t protected_buffer_size_to_send = protected_buffer_size; size_t processed_message_size = message_size; result = tsi_frame_protector_protect(protector, message_bytes, &processed_message_size, protected_buffer, &protected_buffer_size_to_send); if (result != TSI_OK) break; send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); message_bytes += processed_message_size; message_size -= processed_message_size; // Don't forget to flush. if (message_size == 0) { size_t still_pending_size; do { protected_buffer_size_to_send = protected_buffer_size; result = tsi_frame_protector_protect_flush( protector, protected_buffer, &protected_buffer_size_to_send, &still_pending_size); if (result != TSI_OK) break; send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); } while (still_pending_size > 0); } } if (result != TSI_OK) HandleError(result); ------------------------------------------------------------------------ */ tsi_result tsi_frame_protector_protect(tsi_frame_protector* self, const unsigned char* unprotected_bytes, size_t* unprotected_bytes_size, unsigned char* protected_output_frames, size_t* protected_output_frames_size); /* Indicates that we need to flush the bytes buffered in the protector and get the resulting frame. - protected_output_frames points to a buffer allocated by the caller that will be written. - protected_output_frames_size is an input/output parameter used by the caller to specify how many bytes are available in protected_output_frames. - still_pending_bytes is an output parameter indicating the number of bytes that still need to be flushed from the protector.*/ tsi_result tsi_frame_protector_protect_flush( tsi_frame_protector* self, unsigned char* protected_output_frames, size_t* protected_output_frames_size, size_t* still_pending_size); /* Outputs unprotected bytes. - protected_frames_bytes is an input only parameter and points to the protected frames to be unprotected. - protected_frames_bytes_size is an input/output only parameter used by the caller to specify how many bytes are available in protected_bytes. The output value is the number of bytes consumed during the call. Implementations will buffer up to a frame of protected data. - unprotected_bytes points to a buffer allocated by the caller that will be written. - unprotected_bytes_size is an input/output parameter used by the caller to specify how many bytes are available in unprotected_bytes. This value is expected to be at most max_protected_frame_size minus overhead which means that max_protected_frame_size is a safe bet. The output value is the number of bytes actually written. If *unprotected_bytes_size is unchanged, there may be more data remaining to unprotect, and the caller should call this function again. - This method returns TSI_OK in case of success. Success includes cases where there is not enough data to output a frame in which case unprotected_bytes_size will be set to 0 and cases where the internal buffer needs to be read before new protected data can be processed in which case protected_frames_size will be set to 0. */ tsi_result tsi_frame_protector_unprotect( tsi_frame_protector* self, const unsigned char* protected_frames_bytes, size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, size_t* unprotected_bytes_size); /* Destroys the tsi_frame_protector object. */ void tsi_frame_protector_destroy(tsi_frame_protector* self); /* --- tsi_peer objects --- tsi_peer objects are a set of properties. The peer owns the properties. */ /* This property is of type TSI_PEER_PROPERTY_STRING. */ #define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type" /* Property values may contain NULL characters just like C++ strings. The length field gives the length of the string. */ typedef struct tsi_peer_property { char* name; struct { char* data; size_t length; } value; } tsi_peer_property; typedef struct { tsi_peer_property* properties; size_t property_count; } tsi_peer; /* Destructs the tsi_peer object. */ void tsi_peer_destruct(tsi_peer* self); /* --- tsi_handshaker objects ---- Implementations of this object must be thread compatible. A typical usage of this object would be: ------------------------------------------------------------------------ tsi_result result = TSI_OK; unsigned char buf[4096]; size_t buf_offset; size_t buf_size; while (1) { // See if we need to send some bytes to the peer. do { size_t buf_size_to_send = sizeof(buf); result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf, &buf_size_to_send); if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send); } while (result == TSI_INCOMPLETE_DATA); if (result != TSI_OK) return result; if (!tsi_handshaker_is_in_progress(handshaker)) break; do { // Read bytes from the peer. buf_size = sizeof(buf); buf_offset = 0; read_bytes_from_peer(buf, &buf_size); if (buf_size == 0) break; // Process the bytes from the peer. We have to be careful as these bytes // may contain non-handshake data (protected data). If this is the case, // we will exit from the loop with buf_size > 0. size_t consumed_by_handshaker = buf_size; result = tsi_handshaker_process_bytes_from_peer( handshaker, buf, &consumed_by_handshaker); buf_size -= consumed_by_handshaker; buf_offset += consumed_by_handshaker; } while (result == TSI_INCOMPLETE_DATA); if (result != TSI_OK) return result; if (!tsi_handshaker_is_in_progress(handshaker)) break; } // Check the Peer. tsi_peer peer; do { result = tsi_handshaker_extract_peer(handshaker, &peer); if (result != TSI_OK) break; result = check_peer(&peer); } while (0); tsi_peer_destruct(&peer); if (result != TSI_OK) return result; // Create the protector. tsi_frame_protector* protector = NULL; result = tsi_handshaker_create_frame_protector(handshaker, NULL, &protector); if (result != TSI_OK) return result; // Do not forget to unprotect outstanding data if any. if (buf_size > 0) { result = tsi_frame_protector_unprotect(protector, buf + buf_offset, buf_size, ..., ...); .... } ... ------------------------------------------------------------------------ */ typedef struct tsi_handshaker tsi_handshaker; /* Gets bytes that need to be sent to the peer. - bytes is the buffer that will be written with the data to be sent to the peer. - bytes_size is an input/output parameter specifying the capacity of the bytes parameter as input and the number of bytes written as output. Returns TSI_OK if all the data to send to the peer has been written or if nothing has to be sent to the peer (in which base bytes_size outputs to 0), otherwise returns TSI_INCOMPLETE_DATA which indicates that this method needs to be called again to get all the bytes to send to the peer (there was more data to write than the specified bytes_size). In case of a fatal error in the handshake, another specific error code is returned. */ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self, unsigned char* bytes, size_t* bytes_size); /* Processes bytes received from the peer. - bytes is the buffer containing the data. - bytes_size is an input/output parameter specifying the size of the data as input and the number of bytes consumed as output. Return TSI_OK if the handshake has all the data it needs to process, otherwise return TSI_INCOMPLETE_DATA which indicates that this method needs to be called again to complete the data needed for processing. In case of a fatal error in the handshake, another specific error code is returned. */ tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size); /* Gets the result of the handshaker. Returns TSI_OK if the hanshake completed successfully and there has been no errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet but no error has been encountered so far. Otherwise the handshaker failed with the returned error. */ tsi_result tsi_handshaker_get_result(tsi_handshaker* self); /* Returns 1 if the handshake is in progress, 0 otherwise. */ #define tsi_handshaker_is_in_progress(h) \ (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS) /* This method may return TSI_FAILED_PRECONDITION if tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming the handshaker is not in a fatal error state. The caller is responsible for destructing the peer. */ tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer); /* This method creates a tsi_frame_protector object after the handshake phase is done. After this method has been called successfully, the only method that can be called on this object is Destroy. - max_output_protected_frame_size is an input/output parameter specifying the desired max output protected frame size as input and outputing the actual max output frame size as the output. Passing NULL is OK and will result in the implementation choosing the default maximum protected frame size. Note that this size only applies to outgoing frames (generated with tsi_frame_protector_protect) and not incoming frames (input of tsi_frame_protector_unprotect). - protector is an output parameter pointing to the newly created tsi_frame_protector object. This method may return TSI_FAILED_PRECONDITION if tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming the handshaker is not in a fatal error state. The caller is responsible for destroying the protector. */ tsi_result tsi_handshaker_create_frame_protector( tsi_handshaker* self, size_t* max_output_protected_frame_size, tsi_frame_protector** protector); /* This method releases the tsi_handshaker object. After this method is called, no other method can be called on the object. */ void tsi_handshaker_destroy(tsi_handshaker* self); #ifdef __cplusplus } #endif #endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ grpc-0.11.1/src/cpp/0000755000175000017500000000000012600663151014270 5ustar apollockapollockgrpc-0.11.1/src/cpp/README.md0000644000175000017500000000017412600663151015551 0ustar apollockapollock #Overview This directory contains source code for C++ implementation of gRPC. #Status Alpha : Ready for early adopters grpc-0.11.1/src/cpp/proto/0000755000175000017500000000000012600663151015433 5ustar apollockapollockgrpc-0.11.1/src/cpp/proto/proto_utils.cc0000644000175000017500000001324512600663151020332 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include const int kMaxBufferLength = 8192; class GrpcBufferWriter GRPC_FINAL : public ::grpc::protobuf::io::ZeroCopyOutputStream { public: explicit GrpcBufferWriter(grpc_byte_buffer** bp, int block_size = kMaxBufferLength) : block_size_(block_size), byte_count_(0), have_backup_(false) { *bp = grpc_raw_byte_buffer_create(NULL, 0); slice_buffer_ = &(*bp)->data.raw.slice_buffer; } ~GrpcBufferWriter() GRPC_OVERRIDE { if (have_backup_) { gpr_slice_unref(backup_slice_); } } bool Next(void** data, int* size) GRPC_OVERRIDE { if (have_backup_) { slice_ = backup_slice_; have_backup_ = false; } else { slice_ = gpr_slice_malloc(block_size_); } *data = GPR_SLICE_START_PTR(slice_); byte_count_ += * size = GPR_SLICE_LENGTH(slice_); gpr_slice_buffer_add(slice_buffer_, slice_); return true; } void BackUp(int count) GRPC_OVERRIDE { gpr_slice_buffer_pop(slice_buffer_); if (count == block_size_) { backup_slice_ = slice_; } else { backup_slice_ = gpr_slice_split_tail(&slice_, GPR_SLICE_LENGTH(slice_) - count); gpr_slice_buffer_add(slice_buffer_, slice_); } have_backup_ = true; byte_count_ -= count; } grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; } private: const int block_size_; gpr_int64 byte_count_; gpr_slice_buffer* slice_buffer_; bool have_backup_; gpr_slice backup_slice_; gpr_slice slice_; }; class GrpcBufferReader GRPC_FINAL : public ::grpc::protobuf::io::ZeroCopyInputStream { public: explicit GrpcBufferReader(grpc_byte_buffer* buffer) : byte_count_(0), backup_count_(0) { grpc_byte_buffer_reader_init(&reader_, buffer); } ~GrpcBufferReader() GRPC_OVERRIDE { grpc_byte_buffer_reader_destroy(&reader_); } bool Next(const void** data, int* size) GRPC_OVERRIDE { if (backup_count_ > 0) { *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) - backup_count_; *size = backup_count_; backup_count_ = 0; return true; } if (!grpc_byte_buffer_reader_next(&reader_, &slice_)) { return false; } gpr_slice_unref(slice_); *data = GPR_SLICE_START_PTR(slice_); byte_count_ += * size = GPR_SLICE_LENGTH(slice_); return true; } void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; } bool Skip(int count) GRPC_OVERRIDE { const void* data; int size; while (Next(&data, &size)) { if (size >= count) { BackUp(size - count); return true; } // size < count; count -= size; } // error or we have too large count; return false; } grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_ - backup_count_; } private: gpr_int64 byte_count_; gpr_int64 backup_count_; grpc_byte_buffer_reader reader_; gpr_slice slice_; }; namespace grpc { Status SerializeProto(const grpc::protobuf::Message& msg, grpc_byte_buffer** bp) { GrpcBufferWriter writer(bp); return msg.SerializeToZeroCopyStream(&writer) ? Status::OK : Status(StatusCode::INTERNAL, "Failed to serialize message"); } Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg, int max_message_size) { if (!buffer) { return Status(StatusCode::INTERNAL, "No payload"); } GrpcBufferReader reader(buffer); ::grpc::protobuf::io::CodedInputStream decoder(&reader); if (max_message_size > 0) { decoder.SetTotalBytesLimit(max_message_size, max_message_size); } if (!msg->ParseFromCodedStream(&decoder)) { return Status(StatusCode::INTERNAL, msg->InitializationErrorString()); } if (!decoder.ConsumedEntireMessage()) { return Status(StatusCode::INTERNAL, "Did not read entire message"); } return Status::OK; } } // namespace grpc grpc-0.11.1/src/cpp/util/0000755000175000017500000000000012600663151015245 5ustar apollockapollockgrpc-0.11.1/src/cpp/util/time.cc0000644000175000017500000000701212600663151016512 0ustar apollockapollock/* * * 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 #ifndef GRPC_CXX0X_NO_CHRONO #include #include using std::chrono::duration_cast; using std::chrono::nanoseconds; using std::chrono::seconds; using std::chrono::system_clock; using std::chrono::high_resolution_clock; namespace grpc { void Timepoint2Timespec(const system_clock::time_point& from, gpr_timespec* to) { system_clock::duration deadline = from.time_since_epoch(); seconds secs = duration_cast(deadline); if (from == system_clock::time_point::max() || secs.count() >= gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec || secs.count() < 0) { *to = gpr_inf_future(GPR_CLOCK_REALTIME); return; } nanoseconds nsecs = duration_cast(deadline - secs); to->tv_sec = secs.count(); to->tv_nsec = nsecs.count(); to->clock_type = GPR_CLOCK_REALTIME; } void TimepointHR2Timespec(const high_resolution_clock::time_point& from, gpr_timespec* to) { high_resolution_clock::duration deadline = from.time_since_epoch(); seconds secs = duration_cast(deadline); if (from == high_resolution_clock::time_point::max() || secs.count() >= gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec || secs.count() < 0) { *to = gpr_inf_future(GPR_CLOCK_REALTIME); return; } nanoseconds nsecs = duration_cast(deadline - secs); to->tv_sec = secs.count(); to->tv_nsec = nsecs.count(); to->clock_type = GPR_CLOCK_REALTIME; } system_clock::time_point Timespec2Timepoint(gpr_timespec t) { if (gpr_time_cmp(t, gpr_inf_future(t.clock_type)) == 0) { return system_clock::time_point::max(); } t = gpr_convert_clock_type(t, GPR_CLOCK_REALTIME); system_clock::time_point tp; tp += duration_cast(seconds(t.tv_sec)); tp += duration_cast(nanoseconds(t.tv_nsec)); return tp; } } // namespace grpc #endif // !GRPC_CXX0X_NO_CHRONO grpc-0.11.1/src/cpp/util/string_ref.cc0000644000175000017500000000704012600663151017717 0ustar apollockapollock/* * * 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 #include #include #include namespace grpc { const size_t string_ref::npos; string_ref& string_ref::operator=(const string_ref& rhs) { data_ = rhs.data_; length_ = rhs.length_; return *this; } string_ref::string_ref(const char* s) : data_(s), length_(strlen(s)) {} string_ref string_ref::substr(size_t pos, size_t n) const { if (pos > length_) pos = length_; if (n > (length_ - pos)) n = length_ - pos; return string_ref(data_ + pos, n); } int string_ref::compare(string_ref x) const { size_t min_size = length_ < x.length_ ? length_ : x.length_; int r = memcmp(data_, x.data_, min_size); if (r < 0) return -1; if (r > 0) return 1; if (length_ < x.length_) return -1; if (length_ > x.length_) return 1; return 0; } bool string_ref::starts_with(string_ref x) const { return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0); } bool string_ref::ends_with(string_ref x) const { return length_ >= x.length_ && (memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0); } size_t string_ref::find(string_ref s) const { auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend()); return it == cend() ? npos : std::distance(cbegin(), it); } size_t string_ref::find(char c) const { auto it = std::find(cbegin(), cend(), c); return it == cend() ? npos : std::distance(cbegin(), it); } bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; } bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; } bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; } bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; } bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; } bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; } std::ostream& operator<<(std::ostream& out, const string_ref& string) { return out << grpc::string(string.begin(), string.end()); } } // namespace grpc grpc-0.11.1/src/cpp/util/byte_buffer.cc0000644000175000017500000000514512600663151020055 0ustar apollockapollock/* * * 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 #include namespace grpc { ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) { // TODO(yangg) maybe expose some core API to simplify this std::vector c_slices(nslices); for (size_t i = 0; i < nslices; i++) { c_slices[i] = slices[i].slice_; } buffer_ = grpc_raw_byte_buffer_create(c_slices.data(), nslices); } ByteBuffer::~ByteBuffer() { if (buffer_) { grpc_byte_buffer_destroy(buffer_); } } void ByteBuffer::Clear() { if (buffer_) { grpc_byte_buffer_destroy(buffer_); buffer_ = nullptr; } } void ByteBuffer::Dump(std::vector* slices) const { slices->clear(); if (!buffer_) { return; } grpc_byte_buffer_reader reader; grpc_byte_buffer_reader_init(&reader, buffer_); gpr_slice s; while (grpc_byte_buffer_reader_next(&reader, &s)) { slices->push_back(Slice(s, Slice::STEAL_REF)); } } size_t ByteBuffer::Length() const { if (buffer_) { return grpc_byte_buffer_length(buffer_); } else { return 0; } } } // namespace grpc grpc-0.11.1/src/cpp/util/slice.cc0000644000175000017500000000363112600663151016656 0ustar apollockapollock/* * * 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 namespace grpc { Slice::Slice() : slice_(gpr_empty_slice()) {} Slice::~Slice() { gpr_slice_unref(slice_); } Slice::Slice(gpr_slice slice, AddRef) : slice_(gpr_slice_ref(slice)) {} Slice::Slice(gpr_slice slice, StealRef) : slice_(slice) {} Slice::Slice(const Slice& other) : slice_(gpr_slice_ref(other.slice_)) {} } // namespace grpc grpc-0.11.1/src/cpp/util/status.cc0000644000175000017500000000333012600663151017076 0ustar apollockapollock/* * * 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 namespace grpc { const Status& Status::OK = Status(); const Status& Status::CANCELLED = Status(StatusCode::CANCELLED, ""); } // namespace grpc grpc-0.11.1/src/cpp/common/0000755000175000017500000000000012600663151015560 5ustar apollockapollockgrpc-0.11.1/src/cpp/common/secure_auth_context.cc0000644000175000017500000001025012600663151022140 0ustar apollockapollock/* * * 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/cpp/common/secure_auth_context.h" #include namespace grpc { SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx, bool take_ownership) : ctx_(ctx), take_ownership_(take_ownership) {} SecureAuthContext::~SecureAuthContext() { if (take_ownership_) grpc_auth_context_release(ctx_); } std::vector SecureAuthContext::GetPeerIdentity() const { if (!ctx_) { return std::vector(); } grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_); std::vector identity; const grpc_auth_property* property = nullptr; while ((property = grpc_auth_property_iterator_next(&iter))) { identity.push_back( grpc::string_ref(property->value, property->value_length)); } return identity; } grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const { if (!ctx_) { return ""; } const char* name = grpc_auth_context_peer_identity_property_name(ctx_); return name == nullptr ? "" : name; } std::vector SecureAuthContext::FindPropertyValues( const grpc::string& name) const { if (!ctx_) { return std::vector(); } grpc_auth_property_iterator iter = grpc_auth_context_find_properties_by_name(ctx_, name.c_str()); const grpc_auth_property* property = nullptr; std::vector values; while ((property = grpc_auth_property_iterator_next(&iter))) { values.push_back(grpc::string_ref(property->value, property->value_length)); } return values; } AuthPropertyIterator SecureAuthContext::begin() const { if (ctx_) { grpc_auth_property_iterator iter = grpc_auth_context_property_iterator(ctx_); const grpc_auth_property* property = grpc_auth_property_iterator_next(&iter); return AuthPropertyIterator(property, &iter); } else { return end(); } } AuthPropertyIterator SecureAuthContext::end() const { return AuthPropertyIterator(); } void SecureAuthContext::AddProperty(const grpc::string& key, const grpc::string_ref& value) { if (!ctx_) return; grpc_auth_context_add_property(ctx_, key.c_str(), value.data(), value.size()); } bool SecureAuthContext::SetPeerIdentityPropertyName(const grpc::string& name) { if (!ctx_) return false; return grpc_auth_context_set_peer_identity_property_name(ctx_, name.c_str()) != 0; } bool SecureAuthContext::IsPeerAuthenticated() const { if (!ctx_) return false; return grpc_auth_context_peer_is_authenticated(ctx_) != 0; } } // namespace grpc grpc-0.11.1/src/cpp/common/call.cc0000644000175000017500000000666512600663151017017 0ustar apollockapollock/* * * 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 #include #include #include #include #include "src/core/profiling/timers.h" namespace grpc { void FillMetadataMap( grpc_metadata_array* arr, std::multimap* metadata) { for (size_t i = 0; i < arr->count; i++) { // TODO(yangg) handle duplicates? metadata->insert(std::pair( arr->metadata[i].key, grpc::string_ref(arr->metadata[i].value, arr->metadata[i].value_length))); } grpc_metadata_array_destroy(arr); grpc_metadata_array_init(arr); } // TODO(yangg) if the map is changed before we send, the pointers will be a // mess. Make sure it does not happen. grpc_metadata* FillMetadataArray( const std::multimap& metadata) { if (metadata.empty()) { return nullptr; } grpc_metadata* metadata_array = (grpc_metadata*)gpr_malloc(metadata.size() * sizeof(grpc_metadata)); size_t i = 0; for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) { metadata_array[i].key = iter->first.c_str(); metadata_array[i].value = iter->second.c_str(); metadata_array[i].value_length = iter->second.size(); } return metadata_array; } Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq) : call_hook_(call_hook), cq_(cq), call_(call), max_message_size_(-1) {} Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq, int max_message_size) : call_hook_(call_hook), cq_(cq), call_(call), max_message_size_(max_message_size) {} void Call::PerformOps(CallOpSetInterface* ops) { if (max_message_size_ > 0) { ops->set_max_message_size(max_message_size_); } call_hook_->PerformOpsOnCall(ops, this); } } // namespace grpc grpc-0.11.1/src/cpp/common/rpc_method.cc0000644000175000017500000000315412600663151020216 0ustar apollockapollock/* * * 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 namespace grpc {} // namespace grpc grpc-0.11.1/src/cpp/common/insecure_create_auth_context.cc0000644000175000017500000000344512600663151024022 0ustar apollockapollock/* * * 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 #include #include namespace grpc { std::shared_ptr CreateAuthContext(grpc_call* call) { (void)call; return std::shared_ptr(); } } // namespace grpc grpc-0.11.1/src/cpp/common/auth_property_iterator.cc0000644000175000017500000000567712600663151022724 0ustar apollockapollock/* * * 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 #include namespace grpc { AuthPropertyIterator::AuthPropertyIterator() : property_(nullptr), ctx_(nullptr), index_(0), name_(nullptr) {} AuthPropertyIterator::AuthPropertyIterator( const grpc_auth_property* property, const grpc_auth_property_iterator* iter) : property_(property), ctx_(iter->ctx), index_(iter->index), name_(iter->name) {} AuthPropertyIterator::~AuthPropertyIterator() {} AuthPropertyIterator& AuthPropertyIterator::operator++() { grpc_auth_property_iterator iter = {ctx_, index_, name_}; property_ = grpc_auth_property_iterator_next(&iter); ctx_ = iter.ctx; index_ = iter.index; name_ = iter.name; return *this; } AuthPropertyIterator AuthPropertyIterator::operator++(int) { AuthPropertyIterator tmp(*this); operator++(); return tmp; } bool AuthPropertyIterator::operator==(const AuthPropertyIterator& rhs) const { if (property_ == nullptr || rhs.property_ == nullptr) { return property_ == rhs.property_; } else { return index_ == rhs.index_; } } bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const { return !operator==(rhs); } const AuthProperty AuthPropertyIterator::operator*() { return std::pair( property_->name, grpc::string_ref(property_->value, property_->value_length)); } } // namespace grpc grpc-0.11.1/src/cpp/common/secure_create_auth_context.cc0000644000175000017500000000376512600663151023500 0ustar apollockapollock/* * * 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 #include #include #include #include "src/cpp/common/secure_auth_context.h" namespace grpc { std::shared_ptr CreateAuthContext(grpc_call* call) { if (call == nullptr) { return std::shared_ptr(); } return std::shared_ptr( new SecureAuthContext(grpc_call_auth_context(call), true)); } } // namespace grpc grpc-0.11.1/src/cpp/common/completion_queue.cc0000644000175000017500000000656612600663151021461 0ustar apollockapollock/* * 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 #include #include #include #include namespace grpc { CompletionQueue::CompletionQueue() { cq_ = grpc_completion_queue_create(nullptr); } CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {} CompletionQueue::~CompletionQueue() { grpc_completion_queue_destroy(cq_); } void CompletionQueue::Shutdown() { grpc_completion_queue_shutdown(cq_); } CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal( void** tag, bool* ok, gpr_timespec deadline) { for (;;) { auto ev = grpc_completion_queue_next(cq_, deadline, nullptr); switch (ev.type) { case GRPC_QUEUE_TIMEOUT: return TIMEOUT; case GRPC_QUEUE_SHUTDOWN: return SHUTDOWN; case GRPC_OP_COMPLETE: auto cq_tag = static_cast(ev.tag); *ok = ev.success != 0; *tag = cq_tag; if (cq_tag->FinalizeResult(tag, ok)) { return GOT_EVENT; } break; } } } bool CompletionQueue::Pluck(CompletionQueueTag* tag) { auto deadline = gpr_inf_future(GPR_CLOCK_REALTIME); auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr); bool ok = ev.success != 0; void* ignored = tag; GPR_ASSERT(tag->FinalizeResult(&ignored, &ok)); GPR_ASSERT(ignored == tag); // Ignore mutations by FinalizeResult: Pluck returns the C API status return ev.success != 0; } void CompletionQueue::TryPluck(CompletionQueueTag* tag) { auto deadline = gpr_time_0(GPR_CLOCK_REALTIME); auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr); if (ev.type == GRPC_QUEUE_TIMEOUT) return; bool ok = ev.success != 0; void* ignored = tag; // the tag must be swallowed if using TryPluck GPR_ASSERT(!tag->FinalizeResult(&ignored, &ok)); } } // namespace grpc grpc-0.11.1/src/cpp/common/create_auth_context.h0000644000175000017500000000334512600663151021766 0ustar apollockapollock/* * * 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 #include #include namespace grpc { std::shared_ptr CreateAuthContext(grpc_call* call); } // namespace grpc grpc-0.11.1/src/cpp/common/secure_auth_context.h0000644000175000017500000000520012600663151022001 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H #define GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H #include struct grpc_auth_context; namespace grpc { class SecureAuthContext GRPC_FINAL : public AuthContext { public: SecureAuthContext(grpc_auth_context* ctx, bool take_ownership); ~SecureAuthContext() GRPC_OVERRIDE; bool IsPeerAuthenticated() const GRPC_OVERRIDE; std::vector GetPeerIdentity() const GRPC_OVERRIDE; grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE; std::vector FindPropertyValues( const grpc::string& name) const GRPC_OVERRIDE; AuthPropertyIterator begin() const GRPC_OVERRIDE; AuthPropertyIterator end() const GRPC_OVERRIDE; void AddProperty(const grpc::string& key, const grpc::string_ref& value) GRPC_OVERRIDE; virtual bool SetPeerIdentityPropertyName(const grpc::string& name) GRPC_OVERRIDE; private: grpc_auth_context* ctx_; bool take_ownership_; }; } // namespace grpc #endif // GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H grpc-0.11.1/src/cpp/server/0000755000175000017500000000000012600663151015576 5ustar apollockapollockgrpc-0.11.1/src/cpp/server/async_generic_service.cc0000644000175000017500000000374112600663151022443 0ustar apollockapollock/* * * 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 #include namespace grpc { void AsyncGenericService::RequestCall( GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncGenericCall(ctx, reader_writer, call_cq, notification_cq, tag); } } // namespace grpc grpc-0.11.1/src/cpp/server/fixed_size_thread_pool.h0000644000175000017500000000447012600663151022465 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_FIXED_SIZE_THREAD_POOL_H #define GRPC_INTERNAL_CPP_FIXED_SIZE_THREAD_POOL_H #include #include #include #include #include #include "src/cpp/server/thread_pool_interface.h" namespace grpc { class FixedSizeThreadPool GRPC_FINAL : public ThreadPoolInterface { public: explicit FixedSizeThreadPool(int num_threads); ~FixedSizeThreadPool(); void Add(const std::function& callback) GRPC_OVERRIDE; private: grpc::mutex mu_; grpc::condition_variable cv_; bool shutdown_; std::queue> callbacks_; std::vector threads_; void ThreadFunc(); }; } // namespace grpc #endif // GRPC_INTERNAL_CPP_FIXED_SIZE_THREAD_POOL_H grpc-0.11.1/src/cpp/server/server.cc0000644000175000017500000004341012600663151017415 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include #include #include #include #include #include "src/core/profiling/timers.h" #include "src/cpp/server/thread_pool_interface.h" namespace grpc { class Server::UnimplementedAsyncRequestContext { protected: UnimplementedAsyncRequestContext() : generic_stream_(&server_context_) {} GenericServerContext server_context_; GenericServerAsyncReaderWriter generic_stream_; }; class Server::UnimplementedAsyncRequest GRPC_FINAL : public UnimplementedAsyncRequestContext, public GenericAsyncRequest { public: UnimplementedAsyncRequest(Server* server, ServerCompletionQueue* cq) : GenericAsyncRequest(server, &server_context_, &generic_stream_, cq, cq, NULL, false), server_(server), cq_(cq) {} bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE; ServerContext* context() { return &server_context_; } GenericServerAsyncReaderWriter* stream() { return &generic_stream_; } private: Server* const server_; ServerCompletionQueue* const cq_; }; typedef SneakyCallOpSet UnimplementedAsyncResponseOp; class Server::UnimplementedAsyncResponse GRPC_FINAL : public UnimplementedAsyncResponseOp { public: UnimplementedAsyncResponse(UnimplementedAsyncRequest* request); ~UnimplementedAsyncResponse() { delete request_; } bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE { bool r = UnimplementedAsyncResponseOp::FinalizeResult(tag, status); delete this; return r; } private: UnimplementedAsyncRequest* const request_; }; class Server::ShutdownRequest GRPC_FINAL : public CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) { delete this; return false; } }; class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag { public: SyncRequest(RpcServiceMethod* method, void* tag) : method_(method), tag_(tag), in_flight_(false), has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC || method->method_type() == RpcMethod::SERVER_STREAMING), call_details_(nullptr), cq_(nullptr) { grpc_metadata_array_init(&request_metadata_); } ~SyncRequest() { if (call_details_) { delete call_details_; } grpc_metadata_array_destroy(&request_metadata_); } static SyncRequest* Wait(CompletionQueue* cq, bool* ok) { void* tag = nullptr; *ok = false; if (!cq->Next(&tag, ok)) { return nullptr; } auto* mrd = static_cast(tag); GPR_ASSERT(mrd->in_flight_); return mrd; } static bool AsyncWait(CompletionQueue* cq, SyncRequest** req, bool* ok, gpr_timespec deadline) { void* tag = nullptr; *ok = false; switch (cq->AsyncNext(&tag, ok, deadline)) { case CompletionQueue::TIMEOUT: *req = nullptr; return true; case CompletionQueue::SHUTDOWN: *req = nullptr; return false; case CompletionQueue::GOT_EVENT: *req = static_cast(tag); GPR_ASSERT((*req)->in_flight_); return true; } gpr_log(GPR_ERROR, "Should never reach here"); abort(); } void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); } void TeardownRequest() { grpc_completion_queue_destroy(cq_); cq_ = nullptr; } void Request(grpc_server* server, grpc_completion_queue* notify_cq) { GPR_ASSERT(cq_ && !in_flight_); in_flight_ = true; if (tag_) { GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_registered_call( server, tag_, &call_, &deadline_, &request_metadata_, has_request_payload_ ? &request_payload_ : nullptr, cq_, notify_cq, this)); } else { if (!call_details_) { call_details_ = new grpc_call_details; grpc_call_details_init(call_details_); } GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( server, &call_, call_details_, &request_metadata_, cq_, notify_cq, this)); } } bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE { if (!*status) { grpc_completion_queue_destroy(cq_); } if (call_details_) { deadline_ = call_details_->deadline; grpc_call_details_destroy(call_details_); grpc_call_details_init(call_details_); } return true; } class CallData GRPC_FINAL { public: explicit CallData(Server* server, SyncRequest* mrd) : cq_(mrd->cq_), call_(mrd->call_, server, &cq_, server->max_message_size_), ctx_(mrd->deadline_, mrd->request_metadata_.metadata, mrd->request_metadata_.count), has_request_payload_(mrd->has_request_payload_), request_payload_(mrd->request_payload_), method_(mrd->method_) { ctx_.set_call(mrd->call_); ctx_.cq_ = &cq_; GPR_ASSERT(mrd->in_flight_); mrd->in_flight_ = false; mrd->request_metadata_.count = 0; } ~CallData() { if (has_request_payload_ && request_payload_) { grpc_byte_buffer_destroy(request_payload_); } } void Run() { ctx_.BeginCompletionOp(&call_); method_->handler()->RunHandler(MethodHandler::HandlerParameter( &call_, &ctx_, request_payload_, call_.max_message_size())); request_payload_ = nullptr; void* ignored_tag; bool ignored_ok; cq_.Shutdown(); GPR_ASSERT(cq_.Next(&ignored_tag, &ignored_ok) == false); } private: CompletionQueue cq_; Call call_; ServerContext ctx_; const bool has_request_payload_; grpc_byte_buffer* request_payload_; RpcServiceMethod* const method_; }; private: RpcServiceMethod* const method_; void* const tag_; bool in_flight_; const bool has_request_payload_; grpc_call* call_; grpc_call_details* call_details_; gpr_timespec deadline_; grpc_metadata_array request_metadata_; grpc_byte_buffer* request_payload_; grpc_completion_queue* cq_; }; static grpc_server* CreateServer(int max_message_size) { if (max_message_size > 0) { grpc_arg arg; arg.type = GRPC_ARG_INTEGER; arg.key = const_cast(GRPC_ARG_MAX_MESSAGE_LENGTH); arg.value.integer = max_message_size; grpc_channel_args args = {1, &arg}; return grpc_server_create(&args, nullptr); } else { return grpc_server_create(nullptr, nullptr); } } Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned, int max_message_size) : max_message_size_(max_message_size), started_(false), shutdown_(false), num_running_cb_(0), sync_methods_(new std::list), has_generic_service_(false), server_(CreateServer(max_message_size)), thread_pool_(thread_pool), thread_pool_owned_(thread_pool_owned) { grpc_server_register_completion_queue(server_, cq_.cq(), nullptr); } Server::~Server() { { grpc::unique_lock lock(mu_); if (started_ && !shutdown_) { lock.unlock(); Shutdown(); } } void* got_tag; bool ok; GPR_ASSERT(!cq_.Next(&got_tag, &ok)); grpc_server_destroy(server_); if (thread_pool_owned_) { delete thread_pool_; } delete sync_methods_; } bool Server::RegisterService(const grpc::string* host, RpcService* service) { for (int i = 0; i < service->GetMethodCount(); ++i) { RpcServiceMethod* method = service->GetMethod(i); void* tag = grpc_server_register_method(server_, method->name(), host ? host->c_str() : nullptr); if (!tag) { gpr_log(GPR_DEBUG, "Attempt to register %s multiple times", method->name()); return false; } sync_methods_->emplace_back(method, tag); } return true; } bool Server::RegisterAsyncService(const grpc::string* host, AsynchronousService* service) { GPR_ASSERT(service->server_ == nullptr && "Can only register an asynchronous service against one server."); service->server_ = this; service->request_args_ = new void*[service->method_count_]; for (size_t i = 0; i < service->method_count_; ++i) { void* tag = grpc_server_register_method(server_, service->method_names_[i], host ? host->c_str() : nullptr); if (!tag) { gpr_log(GPR_DEBUG, "Attempt to register %s multiple times", service->method_names_[i]); return false; } service->request_args_[i] = tag; } return true; } void Server::RegisterAsyncGenericService(AsyncGenericService* service) { GPR_ASSERT(service->server_ == nullptr && "Can only register an async generic service against one server."); service->server_ = this; has_generic_service_ = true; } int Server::AddListeningPort(const grpc::string& addr, ServerCredentials* creds) { GPR_ASSERT(!started_); return creds->AddPortToServer(addr, server_); } bool Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { GPR_ASSERT(!started_); started_ = true; grpc_server_start(server_); if (!has_generic_service_) { if (!sync_methods_->empty()) { unknown_method_.reset(new RpcServiceMethod( "unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler)); // Use of emplace_back with just constructor arguments is not accepted // here by gcc-4.4 because it can't match the anonymous nullptr with a // proper constructor implicitly. Construct the object and use push_back. sync_methods_->push_back(SyncRequest(unknown_method_.get(), nullptr)); } for (size_t i = 0; i < num_cqs; i++) { new UnimplementedAsyncRequest(this, cqs[i]); } } // Start processing rpcs. if (!sync_methods_->empty()) { for (auto m = sync_methods_->begin(); m != sync_methods_->end(); m++) { m->SetupRequest(); m->Request(server_, cq_.cq()); } ScheduleCallback(); } return true; } void Server::ShutdownInternal(gpr_timespec deadline) { grpc::unique_lock lock(mu_); if (started_ && !shutdown_) { shutdown_ = true; grpc_server_shutdown_and_notify(server_, cq_.cq(), new ShutdownRequest()); cq_.Shutdown(); // Spin, eating requests until the completion queue is completely shutdown. // If the deadline expires then cancel anything that's pending and keep // spinning forever until the work is actually drained. // Since nothing else needs to touch state guarded by mu_, holding it // through this loop is fine. SyncRequest* request; bool ok; while (SyncRequest::AsyncWait(&cq_, &request, &ok, deadline)) { if (request == NULL) { // deadline expired grpc_server_cancel_all_calls(server_); deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); } else if (ok) { SyncRequest::CallData call_data(this, request); } } // Wait for running callbacks to finish. while (num_running_cb_ != 0) { callback_cv_.wait(lock); } } } void Server::Wait() { grpc::unique_lock lock(mu_); while (num_running_cb_ != 0) { callback_cv_.wait(lock); } } void Server::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { static const size_t MAX_OPS = 8; size_t nops = 0; grpc_op cops[MAX_OPS]; ops->FillOps(cops, &nops); auto result = grpc_call_start_batch(call->call(), cops, nops, ops, nullptr); GPR_ASSERT(GRPC_CALL_OK == result); } Server::BaseAsyncRequest::BaseAsyncRequest( Server* server, ServerContext* context, ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag, bool delete_on_finalize) : server_(server), context_(context), stream_(stream), call_cq_(call_cq), tag_(tag), delete_on_finalize_(delete_on_finalize), call_(nullptr) { memset(&initial_metadata_array_, 0, sizeof(initial_metadata_array_)); } Server::BaseAsyncRequest::~BaseAsyncRequest() {} bool Server::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) { if (*status) { for (size_t i = 0; i < initial_metadata_array_.count; i++) { context_->client_metadata_.insert( std::pair( initial_metadata_array_.metadata[i].key, grpc::string_ref( initial_metadata_array_.metadata[i].value, initial_metadata_array_.metadata[i].value_length))); } } grpc_metadata_array_destroy(&initial_metadata_array_); context_->set_call(call_); context_->cq_ = call_cq_; Call call(call_, server_, call_cq_, server_->max_message_size_); if (*status && call_) { context_->BeginCompletionOp(&call); } // just the pointers inside call are copied here stream_->BindCall(&call); *tag = tag_; if (delete_on_finalize_) { delete this; } return true; } Server::RegisteredAsyncRequest::RegisteredAsyncRequest( Server* server, ServerContext* context, ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag) : BaseAsyncRequest(server, context, stream, call_cq, tag, true) {} void Server::RegisteredAsyncRequest::IssueRequest( void* registered_method, grpc_byte_buffer** payload, ServerCompletionQueue* notification_cq) { grpc_server_request_registered_call( server_->server_, registered_method, &call_, &context_->deadline_, &initial_metadata_array_, payload, call_cq_->cq(), notification_cq->cq(), this); } Server::GenericAsyncRequest::GenericAsyncRequest( Server* server, GenericServerContext* context, ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) : BaseAsyncRequest(server, context, stream, call_cq, tag, delete_on_finalize) { grpc_call_details_init(&call_details_); GPR_ASSERT(notification_cq); GPR_ASSERT(call_cq); grpc_server_request_call(server->server_, &call_, &call_details_, &initial_metadata_array_, call_cq->cq(), notification_cq->cq(), this); } bool Server::GenericAsyncRequest::FinalizeResult(void** tag, bool* status) { // TODO(yangg) remove the copy here. if (*status) { static_cast(context_)->method_ = call_details_.method; static_cast(context_)->host_ = call_details_.host; } gpr_free(call_details_.method); gpr_free(call_details_.host); return BaseAsyncRequest::FinalizeResult(tag, status); } bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag, bool* status) { if (GenericAsyncRequest::FinalizeResult(tag, status) && *status) { new UnimplementedAsyncRequest(server_, cq_); new UnimplementedAsyncResponse(this); } else { delete this; } return false; } Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse( UnimplementedAsyncRequest* request) : request_(request) { Status status(StatusCode::UNIMPLEMENTED, ""); UnknownMethodHandler::FillOps(request_->context(), this); request_->stream()->call_.PerformOps(this); } void Server::ScheduleCallback() { { grpc::unique_lock lock(mu_); num_running_cb_++; } thread_pool_->Add(std::bind(&Server::RunRpc, this)); } void Server::RunRpc() { // Wait for one more incoming rpc. bool ok; auto* mrd = SyncRequest::Wait(&cq_, &ok); if (mrd) { ScheduleCallback(); if (ok) { SyncRequest::CallData cd(this, mrd); { mrd->SetupRequest(); grpc::unique_lock lock(mu_); if (!shutdown_) { mrd->Request(server_, cq_.cq()); } else { // destroy the structure that was created mrd->TeardownRequest(); } } cd.Run(); } } { grpc::unique_lock lock(mu_); num_running_cb_--; if (shutdown_) { callback_cv_.notify_all(); } } } } // namespace grpc grpc-0.11.1/src/cpp/server/thread_pool_interface.h0000644000175000017500000000403312600663151022267 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_THREAD_POOL_INTERFACE_H #define GRPC_INTERNAL_CPP_THREAD_POOL_INTERFACE_H #include namespace grpc { // A thread pool interface for running callbacks. class ThreadPoolInterface { public: virtual ~ThreadPoolInterface() {} // Schedule the given callback for execution. virtual void Add(const std::function& callback) = 0; }; ThreadPoolInterface* CreateDefaultThreadPool(); } // namespace grpc #endif // GRPC_INTERNAL_CPP_THREAD_POOL_INTERFACE_H grpc-0.11.1/src/cpp/server/server_credentials.cc0000644000175000017500000000324612600663151021775 0ustar apollockapollock/* * * 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 namespace grpc { ServerCredentials::~ServerCredentials() {} } // namespace grpc grpc-0.11.1/src/cpp/server/secure_server_credentials.cc0000644000175000017500000001344112600663151023341 0ustar apollockapollock/* * * 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 #include #include #include "src/cpp/common/secure_auth_context.h" #include "src/cpp/server/secure_server_credentials.h" #include namespace grpc { void AuthMetadataProcessorAyncWrapper::Destroy(void *wrapper) { auto* w = reinterpret_cast(wrapper); delete w; } void AuthMetadataProcessorAyncWrapper::Process( void* wrapper, grpc_auth_context* context, const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) { auto* w = reinterpret_cast(wrapper); if (w->processor_ == nullptr) { // Early exit. cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_OK, nullptr); return; } if (w->processor_->IsBlocking()) { w->thread_pool_->Add( std::bind(&AuthMetadataProcessorAyncWrapper::InvokeProcessor, w, context, md, num_md, cb, user_data)); } else { // invoke directly. w->InvokeProcessor(context, md, num_md, cb, user_data); } } void AuthMetadataProcessorAyncWrapper::InvokeProcessor( grpc_auth_context* ctx, const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) { AuthMetadataProcessor::InputMetadata metadata; for (size_t i = 0; i < num_md; i++) { metadata.insert(std::make_pair( md[i].key, grpc::string_ref(md[i].value, md[i].value_length))); } SecureAuthContext context(ctx, false); AuthMetadataProcessor::OutputMetadata consumed_metadata; AuthMetadataProcessor::OutputMetadata response_metadata; Status status = processor_->Process(metadata, &context, &consumed_metadata, &response_metadata); std::vector consumed_md; for (auto it = consumed_metadata.begin(); it != consumed_metadata.end(); ++it) { consumed_md.push_back({it->first.c_str(), it->second.data(), it->second.size(), 0, {{nullptr, nullptr, nullptr, nullptr}}}); } std::vector response_md; for (auto it = response_metadata.begin(); it != response_metadata.end(); ++it) { response_md.push_back({it->first.c_str(), it->second.data(), it->second.size(), 0, {{nullptr, nullptr, nullptr, nullptr}}}); } auto consumed_md_data = consumed_md.empty() ? nullptr : &consumed_md[0]; auto response_md_data = response_md.empty() ? nullptr : &response_md[0]; cb(user_data, consumed_md_data, consumed_md.size(), response_md_data, response_md.size(), static_cast(status.error_code()), status.error_message().c_str()); } int SecureServerCredentials::AddPortToServer(const grpc::string& addr, grpc_server* server) { return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); } void SecureServerCredentials::SetAuthMetadataProcessor( const std::shared_ptr& processor) { auto *wrapper = new AuthMetadataProcessorAyncWrapper(processor); grpc_server_credentials_set_auth_metadata_processor( creds_, {AuthMetadataProcessorAyncWrapper::Process, AuthMetadataProcessorAyncWrapper::Destroy, wrapper}); } std::shared_ptr SslServerCredentials( const SslServerCredentialsOptions& options) { std::vector pem_key_cert_pairs; for (auto key_cert_pair = options.pem_key_cert_pairs.begin(); key_cert_pair != options.pem_key_cert_pairs.end(); key_cert_pair++) { grpc_ssl_pem_key_cert_pair p = {key_cert_pair->private_key.c_str(), key_cert_pair->cert_chain.c_str()}; pem_key_cert_pairs.push_back(p); } grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create( options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), pem_key_cert_pairs.empty() ? nullptr : &pem_key_cert_pairs[0], pem_key_cert_pairs.size(), options.force_client_auth, nullptr); return std::shared_ptr( new SecureServerCredentials(c_creds)); } } // namespace grpc grpc-0.11.1/src/cpp/server/server_context.cc0000644000175000017500000001450112600663151021160 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include "src/core/channel/compress_filter.h" #include "src/cpp/common/create_auth_context.h" namespace grpc { // CompletionOp class ServerContext::CompletionOp GRPC_FINAL : public CallOpSetInterface { public: // initial refs: one in the server context, one in the cq CompletionOp() : has_tag_(false), tag_(nullptr), refs_(2), finalized_(false), cancelled_(0) {} void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE; bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE; bool CheckCancelled(CompletionQueue* cq); void set_tag(void* tag) { has_tag_ = true; tag_ = tag; } void Unref(); private: bool has_tag_; void* tag_; grpc::mutex mu_; int refs_; bool finalized_; int cancelled_; }; void ServerContext::CompletionOp::Unref() { grpc::unique_lock lock(mu_); if (--refs_ == 0) { lock.unlock(); delete this; } } bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) { cq->TryPluck(this); grpc::lock_guard g(mu_); return finalized_ ? cancelled_ != 0 : false; } void ServerContext::CompletionOp::FillOps(grpc_op* ops, size_t* nops) { ops->op = GRPC_OP_RECV_CLOSE_ON_SERVER; ops->data.recv_close_on_server.cancelled = &cancelled_; ops->flags = 0; ops->reserved = NULL; *nops = 1; } bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) { grpc::unique_lock lock(mu_); finalized_ = true; bool ret = false; if (has_tag_) { *tag = tag_; ret = true; } if (!*status) cancelled_ = 1; if (--refs_ == 0) { lock.unlock(); delete this; } return ret; } // ServerContext body ServerContext::ServerContext() : completion_op_(nullptr), has_notify_when_done_tag_(false), async_notify_when_done_tag_(nullptr), call_(nullptr), cq_(nullptr), sent_initial_metadata_(false) {} ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata, size_t metadata_count) : completion_op_(nullptr), has_notify_when_done_tag_(false), async_notify_when_done_tag_(nullptr), deadline_(deadline), call_(nullptr), cq_(nullptr), sent_initial_metadata_(false) { for (size_t i = 0; i < metadata_count; i++) { client_metadata_.insert(std::pair( metadata[i].key, grpc::string_ref(metadata[i].value, metadata[i].value_length))); } } ServerContext::~ServerContext() { if (call_) { grpc_call_destroy(call_); } if (completion_op_) { completion_op_->Unref(); } } void ServerContext::BeginCompletionOp(Call* call) { GPR_ASSERT(!completion_op_); completion_op_ = new CompletionOp(); if (has_notify_when_done_tag_) { completion_op_->set_tag(async_notify_when_done_tag_); } call->PerformOps(completion_op_); } void ServerContext::AddInitialMetadata(const grpc::string& key, const grpc::string& value) { initial_metadata_.insert(std::make_pair(key, value)); } void ServerContext::AddTrailingMetadata(const grpc::string& key, const grpc::string& value) { trailing_metadata_.insert(std::make_pair(key, value)); } bool ServerContext::IsCancelled() const { return completion_op_ && completion_op_->CheckCancelled(cq_); } void ServerContext::set_compression_level(grpc_compression_level level) { const grpc_compression_algorithm algorithm_for_level = grpc_compression_algorithm_for_level(level); set_compression_algorithm(algorithm_for_level); } void ServerContext::set_compression_algorithm( grpc_compression_algorithm algorithm) { char* algorithm_name = NULL; if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) { gpr_log(GPR_ERROR, "Name for compression algorithm '%d' unknown.", algorithm); abort(); } GPR_ASSERT(algorithm_name != NULL); AddInitialMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name); } void ServerContext::set_call(grpc_call* call) { call_ = call; auth_context_ = CreateAuthContext(call); } std::shared_ptr ServerContext::auth_context() const { if (auth_context_.get() == nullptr) { auth_context_ = CreateAuthContext(call_); } return auth_context_; } grpc::string ServerContext::peer() const { grpc::string peer; if (call_) { char* c_peer = grpc_call_get_peer(call_); peer = c_peer; gpr_free(c_peer); } return peer; } const struct census_context* ServerContext::census_context() const { return grpc_census_call_get_context(call_); } } // namespace grpc grpc-0.11.1/src/cpp/server/server_builder.cc0000644000175000017500000001204112600663151021117 0ustar apollockapollock/* * * 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 #include #include #include #include #include "src/cpp/server/thread_pool_interface.h" #include "src/cpp/server/fixed_size_thread_pool.h" namespace grpc { ServerBuilder::ServerBuilder() : max_message_size_(-1), generic_service_(nullptr), thread_pool_(nullptr) {} std::unique_ptr ServerBuilder::AddCompletionQueue() { ServerCompletionQueue* cq = new ServerCompletionQueue(); cqs_.push_back(cq); return std::unique_ptr(cq); } void ServerBuilder::RegisterService(SynchronousService* service) { services_.emplace_back(new NamedService(service->service())); } void ServerBuilder::RegisterAsyncService(AsynchronousService* service) { async_services_.emplace_back(new NamedService(service)); } void ServerBuilder::RegisterService(const grpc::string& addr, SynchronousService* service) { services_.emplace_back( new NamedService(addr, service->service())); } void ServerBuilder::RegisterAsyncService(const grpc::string& addr, AsynchronousService* service) { async_services_.emplace_back( new NamedService(addr, service)); } void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) { if (generic_service_) { gpr_log(GPR_ERROR, "Adding multiple AsyncGenericService is unsupported for now. " "Dropping the service %p", service); return; } generic_service_ = service; } void ServerBuilder::AddListeningPort(const grpc::string& addr, std::shared_ptr creds, int* selected_port) { Port port = {addr, creds, selected_port}; ports_.push_back(port); } std::unique_ptr ServerBuilder::BuildAndStart() { bool thread_pool_owned = false; if (!async_services_.empty() && !services_.empty()) { gpr_log(GPR_ERROR, "Mixing async and sync services is unsupported for now"); return nullptr; } if (!thread_pool_ && !services_.empty()) { thread_pool_ = CreateDefaultThreadPool(); thread_pool_owned = true; } std::unique_ptr server( new Server(thread_pool_, thread_pool_owned, max_message_size_)); for (auto cq = cqs_.begin(); cq != cqs_.end(); ++cq) { grpc_server_register_completion_queue(server->server_, (*cq)->cq(), nullptr); } for (auto service = services_.begin(); service != services_.end(); service++) { if (!server->RegisterService((*service)->host.get(), (*service)->service)) { return nullptr; } } for (auto service = async_services_.begin(); service != async_services_.end(); service++) { if (!server->RegisterAsyncService((*service)->host.get(), (*service)->service)) { return nullptr; } } if (generic_service_) { server->RegisterAsyncGenericService(generic_service_); } for (auto port = ports_.begin(); port != ports_.end(); port++) { int r = server->AddListeningPort(port->addr, port->creds.get()); if (!r) return nullptr; if (port->selected_port != nullptr) { *port->selected_port = r; } } auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0]; if (!server->Start(cqs_data, cqs_.size())) { return nullptr; } return server; } } // namespace grpc grpc-0.11.1/src/cpp/server/dynamic_thread_pool.cc0000644000175000017500000001031012600663151022104 0ustar apollockapollock/* * * 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 #include #include "src/cpp/server/dynamic_thread_pool.h" namespace grpc { DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool* pool) : pool_(pool), thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc, this)) {} DynamicThreadPool::DynamicThread::~DynamicThread() { thd_->join(); thd_.reset(); } void DynamicThreadPool::DynamicThread::ThreadFunc() { pool_->ThreadFunc(); // Now that we have killed ourselves, we should reduce the thread count grpc::unique_lock lock(pool_->mu_); pool_->nthreads_--; // Move ourselves to dead list pool_->dead_threads_.push_back(this); if ((pool_->shutdown_) && (pool_->nthreads_ == 0)) { pool_->shutdown_cv_.notify_one(); } } void DynamicThreadPool::ThreadFunc() { for (;;) { // Wait until work is available or we are shutting down. grpc::unique_lock lock(mu_); if (!shutdown_ && callbacks_.empty()) { // If there are too many threads waiting, then quit this thread if (threads_waiting_ >= reserve_threads_) { break; } threads_waiting_++; cv_.wait(lock); threads_waiting_--; } // Drain callbacks before considering shutdown to ensure all work // gets completed. if (!callbacks_.empty()) { auto cb = callbacks_.front(); callbacks_.pop(); lock.unlock(); cb(); } else if (shutdown_) { break; } } } DynamicThreadPool::DynamicThreadPool(int reserve_threads) : shutdown_(false), reserve_threads_(reserve_threads), nthreads_(0), threads_waiting_(0) { for (int i = 0; i < reserve_threads_; i++) { grpc::lock_guard lock(mu_); nthreads_++; new DynamicThread(this); } } void DynamicThreadPool::ReapThreads(std::list* tlist) { for (auto t = tlist->begin(); t != tlist->end(); t = tlist->erase(t)) { delete *t; } } DynamicThreadPool::~DynamicThreadPool() { grpc::unique_lock lock(mu_); shutdown_ = true; cv_.notify_all(); while (nthreads_ != 0) { shutdown_cv_.wait(lock); } ReapThreads(&dead_threads_); } void DynamicThreadPool::Add(const std::function& callback) { grpc::lock_guard lock(mu_); // Add works to the callbacks list callbacks_.push(callback); // Increase pool size or notify as needed if (threads_waiting_ == 0) { // Kick off a new thread nthreads_++; new DynamicThread(this); } else { cv_.notify_one(); } // Also use this chance to harvest dead threads if (!dead_threads_.empty()) { ReapThreads(&dead_threads_); } } } // namespace grpc grpc-0.11.1/src/cpp/server/create_default_thread_pool.cc0000644000175000017500000000360612600663151023441 0ustar apollockapollock/* * * 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 #include "src/cpp/server/dynamic_thread_pool.h" #ifndef GRPC_CUSTOM_DEFAULT_THREAD_POOL namespace grpc { ThreadPoolInterface* CreateDefaultThreadPool() { int cores = gpr_cpu_num_cores(); if (!cores) cores = 4; return new DynamicThreadPool(cores); } } // namespace grpc #endif // !GRPC_CUSTOM_DEFAULT_THREAD_POOL grpc-0.11.1/src/cpp/server/insecure_server_credentials.cc0000644000175000017500000000451112600663151023666 0ustar apollockapollock/* * * 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 #include #include namespace grpc { namespace { class InsecureServerCredentialsImpl GRPC_FINAL : public ServerCredentials { public: int AddPortToServer(const grpc::string& addr, grpc_server* server) GRPC_OVERRIDE { return grpc_server_add_insecure_http2_port(server, addr.c_str()); } void SetAuthMetadataProcessor( const std::shared_ptr& processor) GRPC_OVERRIDE { (void)processor; GPR_ASSERT(0); // Should not be called on InsecureServerCredentials. } }; } // namespace std::shared_ptr InsecureServerCredentials() { return std::shared_ptr( new InsecureServerCredentialsImpl()); } } // namespace grpc grpc-0.11.1/src/cpp/server/fixed_size_thread_pool.cc0000644000175000017500000000544712600663151022630 0ustar apollockapollock/* * * 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 #include #include "src/cpp/server/fixed_size_thread_pool.h" namespace grpc { void FixedSizeThreadPool::ThreadFunc() { for (;;) { // Wait until work is available or we are shutting down. grpc::unique_lock lock(mu_); if (!shutdown_ && callbacks_.empty()) { cv_.wait(lock); } // Drain callbacks before considering shutdown to ensure all work // gets completed. if (!callbacks_.empty()) { auto cb = callbacks_.front(); callbacks_.pop(); lock.unlock(); cb(); } else if (shutdown_) { return; } } } FixedSizeThreadPool::FixedSizeThreadPool(int num_threads) : shutdown_(false) { for (int i = 0; i < num_threads; i++) { threads_.push_back( new grpc::thread(&FixedSizeThreadPool::ThreadFunc, this)); } } FixedSizeThreadPool::~FixedSizeThreadPool() { { grpc::lock_guard lock(mu_); shutdown_ = true; cv_.notify_all(); } for (auto t = threads_.begin(); t != threads_.end(); t++) { (*t)->join(); delete *t; } } void FixedSizeThreadPool::Add(const std::function& callback) { grpc::lock_guard lock(mu_); callbacks_.push(callback); cv_.notify_one(); } } // namespace grpc grpc-0.11.1/src/cpp/server/dynamic_thread_pool.h0000644000175000017500000000527412600663151021763 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_DYNAMIC_THREAD_POOL_H #define GRPC_INTERNAL_CPP_DYNAMIC_THREAD_POOL_H #include #include #include #include #include #include #include "src/cpp/server/thread_pool_interface.h" namespace grpc { class DynamicThreadPool GRPC_FINAL : public ThreadPoolInterface { public: explicit DynamicThreadPool(int reserve_threads); ~DynamicThreadPool(); void Add(const std::function& callback) GRPC_OVERRIDE; private: class DynamicThread { public: DynamicThread(DynamicThreadPool* pool); ~DynamicThread(); private: DynamicThreadPool* pool_; std::unique_ptr thd_; void ThreadFunc(); }; grpc::mutex mu_; grpc::condition_variable cv_; grpc::condition_variable shutdown_cv_; bool shutdown_; std::queue> callbacks_; int reserve_threads_; int nthreads_; int threads_waiting_; std::list dead_threads_; void ThreadFunc(); static void ReapThreads(std::list* tlist); }; } // namespace grpc #endif // GRPC_INTERNAL_CPP_DYNAMIC_THREAD_POOL_H grpc-0.11.1/src/cpp/server/secure_server_credentials.h0000644000175000017500000000641612600663151023207 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H #define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H #include #include #include #include "src/cpp/server/thread_pool_interface.h" namespace grpc { class AuthMetadataProcessorAyncWrapper GRPC_FINAL { public: static void Destroy(void *wrapper); static void Process(void* wrapper, grpc_auth_context* context, const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data); AuthMetadataProcessorAyncWrapper( const std::shared_ptr& processor) : thread_pool_(CreateDefaultThreadPool()), processor_(processor) {} private: void InvokeProcessor(grpc_auth_context* context, const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data); std::unique_ptr thread_pool_; std::shared_ptr processor_; }; class SecureServerCredentials GRPC_FINAL : public ServerCredentials { public: explicit SecureServerCredentials(grpc_server_credentials* creds) : creds_(creds) {} ~SecureServerCredentials() GRPC_OVERRIDE { grpc_server_credentials_release(creds_); } int AddPortToServer(const grpc::string& addr, grpc_server* server) GRPC_OVERRIDE; void SetAuthMetadataProcessor( const std::shared_ptr& processor) GRPC_OVERRIDE; private: grpc_server_credentials* creds_; std::unique_ptr processor_; }; } // namespace grpc #endif // GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H grpc-0.11.1/src/cpp/client/0000755000175000017500000000000012600663151015546 5ustar apollockapollockgrpc-0.11.1/src/cpp/client/create_channel_internal.h0000644000175000017500000000375612600663151022561 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_CLIENT_CREATE_CHANNEL_INTERNAL_H #define GRPC_INTERNAL_CPP_CLIENT_CREATE_CHANNEL_INTERNAL_H #include #include struct grpc_channel; namespace grpc { class Channel; std::shared_ptr CreateChannelInternal(const grpc::string& host, grpc_channel* c_channel); } // namespace grpc #endif // GRPC_INTERNAL_CPP_CLIENT_CREATE_CHANNEL_INTERNAL_H grpc-0.11.1/src/cpp/client/generic_stub.cc0000644000175000017500000000406012600663151020526 0ustar apollockapollock/* * * 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 #include namespace grpc { // begin a call to a named method std::unique_ptr GenericStub::Call( ClientContext* context, const grpc::string& method, CompletionQueue* cq, void* tag) { return std::unique_ptr( new GenericClientAsyncReaderWriter( channel_.get(), cq, RpcMethod(method.c_str(), RpcMethod::BIDI_STREAMING), context, tag)); } } // namespace grpc grpc-0.11.1/src/cpp/client/secure_channel_arguments.cc0000644000175000017500000000411012600663151023114 0ustar apollockapollock/* * * 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 #include #include "src/core/channel/channel_args.h" namespace grpc { void ChannelArguments::SetSslTargetNameOverride(const grpc::string& name) { SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name); } grpc::string ChannelArguments::GetSslTargetNameOverride() const { for (unsigned int i = 0; i < args_.size(); i++) { if (grpc::string(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == args_[i].key) { return args_[i].value.string; } } return ""; } } // namespace grpc grpc-0.11.1/src/cpp/client/credentials.cc0000644000175000017500000000322312600663151020352 0ustar apollockapollock/* * * 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 namespace grpc { Credentials::~Credentials() {} } // namespace grpc grpc-0.11.1/src/cpp/client/channel_arguments.cc0000644000175000017500000000740012600663151021553 0ustar apollockapollock/* * * 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 #include #include "src/core/channel/channel_args.h" namespace grpc { ChannelArguments::ChannelArguments(const ChannelArguments& other) : strings_(other.strings_) { args_.reserve(other.args_.size()); auto list_it_dst = strings_.begin(); auto list_it_src = other.strings_.begin(); for (auto a = other.args_.begin(); a != other.args_.end(); ++a) { grpc_arg ap; ap.type = a->type; GPR_ASSERT(list_it_src->c_str() == a->key); ap.key = const_cast(list_it_dst->c_str()); ++list_it_src; ++list_it_dst; switch (a->type) { case GRPC_ARG_INTEGER: ap.value.integer = a->value.integer; break; case GRPC_ARG_STRING: GPR_ASSERT(list_it_src->c_str() == a->value.string); ap.value.string = const_cast(list_it_dst->c_str()); ++list_it_src; ++list_it_dst; break; case GRPC_ARG_POINTER: ap.value.pointer = a->value.pointer; ap.value.pointer.p = a->value.pointer.copy(ap.value.pointer.p); break; } args_.push_back(ap); } } void ChannelArguments::Swap(ChannelArguments& other) { args_.swap(other.args_); strings_.swap(other.strings_); } void ChannelArguments::SetCompressionAlgorithm( grpc_compression_algorithm algorithm) { SetInt(GRPC_COMPRESSION_ALGORITHM_ARG, algorithm); } void ChannelArguments::SetInt(const grpc::string& key, int value) { grpc_arg arg; arg.type = GRPC_ARG_INTEGER; strings_.push_back(key); arg.key = const_cast(strings_.back().c_str()); arg.value.integer = value; args_.push_back(arg); } void ChannelArguments::SetString(const grpc::string& key, const grpc::string& value) { grpc_arg arg; arg.type = GRPC_ARG_STRING; strings_.push_back(key); arg.key = const_cast(strings_.back().c_str()); strings_.push_back(value); arg.value.string = const_cast(strings_.back().c_str()); args_.push_back(arg); } void ChannelArguments::SetChannelArgs(grpc_channel_args* channel_args) const { channel_args->num_args = args_.size(); if (channel_args->num_args > 0) { channel_args->args = const_cast(&args_[0]); } } } // namespace grpc grpc-0.11.1/src/cpp/client/create_channel.cc0000644000175000017500000000534012600663151021012 0ustar apollockapollock/* * * 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 #include #include #include #include #include "src/cpp/client/create_channel_internal.h" namespace grpc { class ChannelArguments; std::shared_ptr CreateChannel( const grpc::string& target, const std::shared_ptr& creds) { return CreateCustomChannel(target, creds, ChannelArguments()); } std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args) { GrpcLibrary init_lib; // We need to call init in case of a bad creds. ChannelArguments cp_args = args; std::ostringstream user_agent_prefix; user_agent_prefix << "grpc-c++/" << grpc_version_string(); cp_args.SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix.str()); return creds ? creds->CreateChannel(target, cp_args) : CreateChannelInternal("", grpc_lame_client_channel_create( NULL, GRPC_STATUS_INVALID_ARGUMENT, "Invalid credentials.")); } } // namespace grpc grpc-0.11.1/src/cpp/client/secure_credentials.h0000644000175000017500000000464412600663151021572 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H #define GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H #include #include #include namespace grpc { class SecureCredentials GRPC_FINAL : public Credentials { public: explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {} ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); } grpc_credentials* GetRawCreds() { return c_creds_; } bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE; std::shared_ptr CreateChannel( const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE; SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; } private: grpc_credentials* const c_creds_; }; } // namespace grpc #endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H grpc-0.11.1/src/cpp/client/secure_credentials.cc0000644000175000017500000001334612600663151021727 0ustar apollockapollock/* * * 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 #include #include #include #include "src/cpp/client/create_channel_internal.h" #include "src/cpp/client/secure_credentials.h" namespace grpc { std::shared_ptr SecureCredentials::CreateChannel( const string& target, const grpc::ChannelArguments& args) { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return CreateChannelInternal( args.GetSslTargetNameOverride(), grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args, nullptr)); } bool SecureCredentials::ApplyToCall(grpc_call* call) { return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK; } namespace { std::shared_ptr WrapCredentials(grpc_credentials* creds) { return creds == nullptr ? nullptr : std::shared_ptr(new SecureCredentials(creds)); } } // namespace std::shared_ptr GoogleDefaultCredentials() { GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_google_default_credentials_create()); } // Builds SSL Credentials given SSL specific options std::shared_ptr SslCredentials( const SslCredentialsOptions& options) { GrpcLibrary init; // To call grpc_init(). grpc_ssl_pem_key_cert_pair pem_key_cert_pair = { options.pem_private_key.c_str(), options.pem_cert_chain.c_str()}; grpc_credentials* c_creds = grpc_ssl_credentials_create( options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr); return WrapCredentials(c_creds); } // Builds credentials for use when running in GCE std::shared_ptr GoogleComputeEngineCredentials() { GrpcLibrary init; // To call grpc_init(). return WrapCredentials( grpc_google_compute_engine_credentials_create(nullptr)); } // Builds JWT credentials. std::shared_ptr ServiceAccountJWTAccessCredentials( const grpc::string& json_key, long token_lifetime_seconds) { GrpcLibrary init; // To call grpc_init(). if (token_lifetime_seconds <= 0) { gpr_log(GPR_ERROR, "Trying to create JWTCredentials with non-positive lifetime"); return WrapCredentials(nullptr); } gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN); return WrapCredentials(grpc_service_account_jwt_access_credentials_create( json_key.c_str(), lifetime, nullptr)); } // Builds refresh token credentials. std::shared_ptr GoogleRefreshTokenCredentials( const grpc::string& json_refresh_token) { GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_google_refresh_token_credentials_create( json_refresh_token.c_str(), nullptr)); } // Builds access token credentials. std::shared_ptr AccessTokenCredentials( const grpc::string& access_token) { GrpcLibrary init; // To call grpc_init(). return WrapCredentials( grpc_access_token_credentials_create(access_token.c_str(), nullptr)); } // Builds IAM credentials. std::shared_ptr GoogleIAMCredentials( const grpc::string& authorization_token, const grpc::string& authority_selector) { GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_google_iam_credentials_create( authorization_token.c_str(), authority_selector.c_str(), nullptr)); } // Combines two credentials objects into a composite credentials. std::shared_ptr CompositeCredentials( const std::shared_ptr& creds1, const std::shared_ptr& creds2) { // Note that we are not saving shared_ptrs to the two credentials // passed in here. This is OK because the underlying C objects (i.e., // creds1 and creds2) into grpc_composite_credentials_create will see their // refcounts incremented. SecureCredentials* s1 = creds1->AsSecureCredentials(); SecureCredentials* s2 = creds2->AsSecureCredentials(); if (s1 && s2) { return WrapCredentials(grpc_composite_credentials_create( s1->GetRawCreds(), s2->GetRawCreds(), nullptr)); } return nullptr; } } // namespace grpc grpc-0.11.1/src/cpp/client/create_channel_internal.cc0000644000175000017500000000354512600663151022713 0ustar apollockapollock/* * * 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 #include struct grpc_channel; namespace grpc { std::shared_ptr CreateChannelInternal(const grpc::string& host, grpc_channel* c_channel) { return std::shared_ptr(new Channel(host, c_channel)); } } // namespace grpc grpc-0.11.1/src/cpp/client/channel.cc0000644000175000017500000001216412600663151017471 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "src/core/profiling/timers.h" namespace grpc { Channel::Channel(const grpc::string& host, grpc_channel* channel) : host_(host), c_channel_(channel) {} Channel::~Channel() { grpc_channel_destroy(c_channel_); } Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, CompletionQueue* cq) { const bool kRegistered = method.channel_tag() && context->authority().empty(); grpc_call* c_call = NULL; if (kRegistered) { c_call = grpc_channel_create_registered_call( c_channel_, context->propagate_from_call_, context->propagation_options_.c_bitmask(), cq->cq(), method.channel_tag(), context->raw_deadline(), nullptr); } else { const char* host_str = NULL; if (!context->authority().empty()) { host_str = context->authority_.c_str(); } else if (!host_.empty()) { host_str = host_.c_str(); } c_call = grpc_channel_create_call(c_channel_, context->propagate_from_call_, context->propagation_options_.c_bitmask(), cq->cq(), method.name(), host_str, context->raw_deadline(), nullptr); } grpc_census_call_set_context(c_call, context->census_context()); GRPC_TIMER_MARK(GRPC_PTAG_CPP_CALL_CREATED, c_call); context->set_call(c_call, shared_from_this()); return Call(c_call, this, cq); } void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { static const size_t MAX_OPS = 8; size_t nops = 0; grpc_op cops[MAX_OPS]; GRPC_TIMER_BEGIN(GRPC_PTAG_CPP_PERFORM_OPS, call->call()); ops->FillOps(cops, &nops); GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), cops, nops, ops, nullptr)); GRPC_TIMER_END(GRPC_PTAG_CPP_PERFORM_OPS, call->call()); } void* Channel::RegisterMethod(const char* method) { return grpc_channel_register_call( c_channel_, method, host_.empty() ? NULL : host_.c_str(), nullptr); } grpc_connectivity_state Channel::GetState(bool try_to_connect) { return grpc_channel_check_connectivity_state(c_channel_, try_to_connect); } namespace { class TagSaver GRPC_FINAL : public CompletionQueueTag { public: explicit TagSaver(void* tag) : tag_(tag) {} ~TagSaver() GRPC_OVERRIDE {} bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE { *tag = tag_; delete this; return true; } private: void* tag_; }; } // namespace void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, CompletionQueue* cq, void* tag) { TagSaver* tag_saver = new TagSaver(tag); grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline, cq->cq(), tag_saver); } bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) { CompletionQueue cq; bool ok = false; void* tag = NULL; NotifyOnStateChangeImpl(last_observed, deadline, &cq, NULL); cq.Next(&tag, &ok); GPR_ASSERT(tag == NULL); return ok; } } // namespace grpc grpc-0.11.1/src/cpp/client/client_context.cc0000644000175000017500000000761412600663151021107 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include #include "src/core/channel/compress_filter.h" #include "src/cpp/common/create_auth_context.h" namespace grpc { ClientContext::ClientContext() : initial_metadata_received_(false), call_(nullptr), deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)), propagate_from_call_(nullptr) {} ClientContext::~ClientContext() { if (call_) { grpc_call_destroy(call_); } } std::unique_ptr ClientContext::FromServerContext( const ServerContext& context, PropagationOptions options) { std::unique_ptr ctx(new ClientContext); ctx->propagate_from_call_ = context.call_; ctx->propagation_options_ = options; return ctx; } void ClientContext::AddMetadata(const grpc::string& meta_key, const grpc::string& meta_value) { send_initial_metadata_.insert(std::make_pair(meta_key, meta_value)); } void ClientContext::set_call(grpc_call* call, const std::shared_ptr& channel) { GPR_ASSERT(call_ == nullptr); call_ = call; channel_ = channel; if (creds_ && !creds_->ApplyToCall(call_)) { grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Failed to set credentials to rpc.", nullptr); } } void ClientContext::set_compression_algorithm( grpc_compression_algorithm algorithm) { char* algorithm_name = nullptr; if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) { gpr_log(GPR_ERROR, "Name for compression algorithm '%d' unknown.", algorithm); abort(); } GPR_ASSERT(algorithm_name != nullptr); AddMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name); } std::shared_ptr ClientContext::auth_context() const { if (auth_context_.get() == nullptr) { auth_context_ = CreateAuthContext(call_); } return auth_context_; } void ClientContext::TryCancel() { if (call_) { grpc_call_cancel(call_, nullptr); } } grpc::string ClientContext::peer() const { grpc::string peer; if (call_) { char* c_peer = grpc_call_get_peer(call_); peer = c_peer; gpr_free(c_peer); } return peer; } } // namespace grpc grpc-0.11.1/src/cpp/client/insecure_credentials.cc0000644000175000017500000000511312600663151022247 0ustar apollockapollock/* * * 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 #include #include #include #include #include #include "src/cpp/client/create_channel_internal.h" namespace grpc { namespace { class InsecureCredentialsImpl GRPC_FINAL : public Credentials { public: std::shared_ptr CreateChannel( const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return CreateChannelInternal( "", grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr)); } // InsecureCredentials should not be applied to a call. bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE { return false; } SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; } }; } // namespace std::shared_ptr InsecureCredentials() { return std::shared_ptr(new InsecureCredentialsImpl()); } } // namespace grpc grpc-0.11.1/src/python/0000755000175000017500000000000012600663151015027 5ustar apollockapollockgrpc-0.11.1/src/python/README.md0000644000175000017500000000410312600663151016304 0ustar apollockapollockgRPC Python ========= The Python facility of gRPC. Status ------- Beta : Core behavior well-used and proven; bugs lurk off the beaten path. PREREQUISITES ------------- - Python 2.7, virtualenv, pip - [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core. INSTALLATION ------------- **Linux (Debian):** Add [Debian jessie-backports][] to your `sources.list` file. Example: ```sh echo "deb http://http.debian.net/debian jessie-backports main" | \ sudo tee -a /etc/apt/sources.list ``` Install the gRPC Debian package ```sh sudo apt-get update sudo apt-get install libgrpc-dev ``` Install the gRPC Python module ```sh sudo pip install grpcio ``` **Mac OS X** Install [homebrew][]. Run the following command to install gRPC Python. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s python ``` This will download and run the [gRPC install script][], then install the latest version of the gRPC Python package. It also installs the Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin for python. EXAMPLES -------- Please read our online documentation for a [Quick Start][] and a [detailed example][] BUILDING FROM SOURCE --------------------- - Clone this repository - Initialize the git submodules ``` $ git submodule update --init ``` - Make the libraries ``` $ make ``` - Use build_python.sh to build the Python code and install it into a virtual environment ``` $ CONFIG=opt tools/run_tests/build_python.sh 2.7 ``` TESTING ------- - Use run_python.sh to run gRPC as it was installed into the virtual environment ``` $ CONFIG=opt PYVER=2.7 tools/run_tests/run_python.sh ``` PACKAGING --------- - Install packaging dependencies ``` $ pip install setuptools twine ``` - Push to PyPI ``` $ ../../tools/distrib/python/submit.py ``` [homebrew]:http://brew.sh [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [Quick Start]:http://www.grpc.io/docs/tutorials/basic/python.html [detailed example]:http://www.grpc.io/docs/installation/python.html [Debian jessie-backports]:http://backports.debian.org/Instructions/ grpc-0.11.1/src/python/grpcio/0000755000175000017500000000000012600663151016312 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/0000755000175000017500000000000012600663151017245 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_cython/0000755000175000017500000000000012600663151020710 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/0000755000175000017500000000000012600663151022336 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/channel.pxd0000644000175000017500000000316212600663151024465 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc cdef class Channel: cdef grpc.grpc_channel *c_channel cdef list references grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd0000644000175000017500000000674712600663151024532 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport server cdef class Timespec: cdef grpc.gpr_timespec c_time cdef class CallDetails: cdef grpc.grpc_call_details c_details cdef class OperationTag: cdef object user_tag cdef list references # This allows CompletionQueue to notify the Python Server object that the # underlying GRPC core server has shutdown cdef server.Server shutting_down_server cdef call.Call operation_call cdef CallDetails request_call_details cdef Metadata request_metadata cdef Operations batch_operations cdef bint is_new_request cdef class Event: cdef readonly grpc.grpc_completion_type type cdef readonly bint success cdef readonly object tag # For operations with calls cdef readonly call.Call operation_call # For Server.request_call cdef readonly CallDetails request_call_details cdef readonly Metadata request_metadata # For Call.start_batch cdef readonly Operations batch_operations cdef class ByteBuffer: cdef grpc.grpc_byte_buffer *c_byte_buffer cdef class SslPemKeyCertPair: cdef grpc.grpc_ssl_pem_key_cert_pair c_pair cdef readonly object private_key, certificate_chain cdef class ChannelArg: cdef grpc.grpc_arg c_arg cdef readonly object key, value cdef class ChannelArgs: cdef grpc.grpc_channel_args c_args cdef list args cdef class Metadatum: cdef grpc.grpc_metadata c_metadata cdef object _key, _value cdef class Metadata: cdef grpc.grpc_metadata_array c_metadata_array cdef object metadata cdef class Operation: cdef grpc.grpc_op c_op cdef ByteBuffer _received_message cdef Metadata _received_metadata cdef grpc.grpc_status_code _received_status_code cdef char *_received_status_details cdef size_t _received_status_details_capacity cdef int _received_cancelled cdef readonly bint is_valid cdef object references cdef class Operations: cdef grpc.grpc_op *c_ops cdef size_t c_nops cdef list operations grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx0000644000175000017500000000641112600663151024015 0ustar apollockapollock# 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. cimport cpython from grpc._cython._cygrpc cimport records cdef class Call: def __cinit__(self): # Create an *empty* call self.c_call = NULL self.references = [] def start_batch(self, operations, tag): if not self.is_valid: raise ValueError("invalid call object cannot be used from Python") cdef records.Operations cy_operations = records.Operations(operations) cdef records.OperationTag operation_tag = records.OperationTag(tag) operation_tag.operation_call = self operation_tag.batch_operations = cy_operations cpython.Py_INCREF(operation_tag) return grpc.grpc_call_start_batch( self.c_call, cy_operations.c_ops, cy_operations.c_nops, operation_tag) def cancel(self, grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE, details=None): if not self.is_valid: raise ValueError("invalid call object cannot be used from Python") if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE): raise ValueError("if error_code is specified, so must details " "(and vice-versa)") if isinstance(details, bytes): pass elif isinstance(details, basestring): details = details.encode() else: raise TypeError("expected details to be str or bytes") if error_code != grpc.GRPC_STATUS__DO_NOT_USE: self.references.append(details) return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details) else: return grpc.grpc_call_cancel(self.c_call) def __dealloc__(self): if self.c_call != NULL: grpc.grpc_call_destroy(self.c_call) # The object *should* always be valid from Python. Used for debugging. @property def is_valid(self): return self.c_call != NULL grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx0000644000175000017500000004425212600663151024550 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport server class StatusCode: ok = grpc.GRPC_STATUS_OK cancelled = grpc.GRPC_STATUS_CANCELLED unknown = grpc.GRPC_STATUS_UNKNOWN invalid_argument = grpc.GRPC_STATUS_INVALID_ARGUMENT deadline_exceeded = grpc.GRPC_STATUS_DEADLINE_EXCEEDED not_found = grpc.GRPC_STATUS_NOT_FOUND already_exists = grpc.GRPC_STATUS_ALREADY_EXISTS permission_denied = grpc.GRPC_STATUS_PERMISSION_DENIED unauthenticated = grpc.GRPC_STATUS_UNAUTHENTICATED resource_exhausted = grpc.GRPC_STATUS_RESOURCE_EXHAUSTED failed_precondition = grpc.GRPC_STATUS_FAILED_PRECONDITION aborted = grpc.GRPC_STATUS_ABORTED out_of_range = grpc.GRPC_STATUS_OUT_OF_RANGE unimplemented = grpc.GRPC_STATUS_UNIMPLEMENTED internal = grpc.GRPC_STATUS_INTERNAL unavailable = grpc.GRPC_STATUS_UNAVAILABLE data_loss = grpc.GRPC_STATUS_DATA_LOSS class CallError: ok = grpc.GRPC_CALL_OK error = grpc.GRPC_CALL_ERROR not_on_server = grpc.GRPC_CALL_ERROR_NOT_ON_SERVER not_on_client = grpc.GRPC_CALL_ERROR_NOT_ON_CLIENT already_accepted = grpc.GRPC_CALL_ERROR_ALREADY_ACCEPTED already_invoked = grpc.GRPC_CALL_ERROR_ALREADY_INVOKED not_invoked = grpc.GRPC_CALL_ERROR_NOT_INVOKED already_finished = grpc.GRPC_CALL_ERROR_ALREADY_FINISHED too_many_operations = grpc.GRPC_CALL_ERROR_TOO_MANY_OPERATIONS invalid_flags = grpc.GRPC_CALL_ERROR_INVALID_FLAGS invalid_metadata = grpc.GRPC_CALL_ERROR_INVALID_METADATA class CompletionType: queue_shutdown = grpc.GRPC_QUEUE_SHUTDOWN queue_timeout = grpc.GRPC_QUEUE_TIMEOUT operation_complete = grpc.GRPC_OP_COMPLETE class OperationType: send_initial_metadata = grpc.GRPC_OP_SEND_INITIAL_METADATA send_message = grpc.GRPC_OP_SEND_MESSAGE send_close_from_client = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT send_status_from_server = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER receive_initial_metadata = grpc.GRPC_OP_RECV_INITIAL_METADATA receive_message = grpc.GRPC_OP_RECV_MESSAGE receive_status_on_client = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT receive_close_on_server = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER cdef class Timespec: def __cinit__(self, time): if time is None: self.c_time = grpc.gpr_now() elif isinstance(time, float): if time == float("+inf"): self.c_time = grpc.gpr_inf_future elif time == float("-inf"): self.c_time = grpc.gpr_inf_past else: self.c_time.seconds = time self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9 else: raise TypeError("expected time to be float") @property def seconds(self): return self.c_time.seconds @property def nanoseconds(self): return self.c_time.nanoseconds def __float__(self): return self.c_time.seconds + self.c_time.nanoseconds / 1e9 infinite_future = Timespec(float("+inf")) infinite_past = Timespec(float("-inf")) cdef class CallDetails: def __cinit__(self): grpc.grpc_call_details_init(&self.c_details) def __dealloc__(self): grpc.grpc_call_details_destroy(&self.c_details) @property def method(self): if self.c_details.method != NULL: return self.c_details.method else: return None @property def host(self): if self.c_details.host != NULL: return self.c_details.host else: return None @property def deadline(self): timespec = Timespec(float("-inf")) timespec.c_time = self.c_details.deadline return timespec cdef class OperationTag: def __cinit__(self, user_tag): self.user_tag = user_tag self.references = [] cdef class Event: def __cinit__(self, grpc.grpc_completion_type type, bint success, object tag, call.Call operation_call, CallDetails request_call_details, Metadata request_metadata, Operations batch_operations): self.type = type self.success = success self.tag = tag self.operation_call = operation_call self.request_call_details = request_call_details self.request_metadata = request_metadata self.batch_operations = batch_operations cdef class ByteBuffer: def __cinit__(self, data): if data is None: self.c_byte_buffer = NULL return if isinstance(data, bytes): pass elif isinstance(data, basestring): data = data.encode() else: raise TypeError("expected value to be of type str or bytes") cdef char *c_data = data data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data)) self.c_byte_buffer = grpc.grpc_raw_byte_buffer_create( &data_slice, 1) grpc.gpr_slice_unref(data_slice) def bytes(self): cdef grpc.grpc_byte_buffer_reader reader cdef grpc.gpr_slice data_slice cdef size_t data_slice_length cdef void *data_slice_pointer if self.c_byte_buffer != NULL: grpc.grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer) result = b"" while grpc.grpc_byte_buffer_reader_next(&reader, &data_slice): data_slice_pointer = grpc.gpr_slice_start_ptr(data_slice) data_slice_length = grpc.gpr_slice_length(data_slice) result += (data_slice_pointer)[:data_slice_length] grpc.grpc_byte_buffer_reader_destroy(&reader) return result else: return None def __len__(self): if self.c_byte_buffer != NULL: return grpc.grpc_byte_buffer_length(self.c_byte_buffer) else: return 0 def __str__(self): return self.bytes() def __dealloc__(self): if self.c_byte_buffer != NULL: grpc.grpc_byte_buffer_destroy(self.c_byte_buffer) cdef class SslPemKeyCertPair: def __cinit__(self, private_key, certificate_chain): if isinstance(private_key, bytes): self.private_key = private_key elif isinstance(private_key, basestring): self.private_key = private_key.encode() else: raise TypeError("expected private_key to be of type str or bytes") if isinstance(certificate_chain, bytes): self.certificate_chain = certificate_chain elif isinstance(certificate_chain, basestring): self.certificate_chain = certificate_chain.encode() else: raise TypeError("expected certificate_chain to be of type str or bytes " "or int") self.c_pair.private_key = self.private_key self.c_pair.certificate_chain = self.certificate_chain cdef class ChannelArg: def __cinit__(self, key, value): if isinstance(key, bytes): self.key = key elif isinstance(key, basestring): self.key = key.encode() else: raise TypeError("expected key to be of type str or bytes") if isinstance(value, bytes): self.value = value self.c_arg.type = grpc.GRPC_ARG_STRING self.c_arg.value.string = self.value elif isinstance(value, basestring): self.value = value.encode() self.c_arg.type = grpc.GRPC_ARG_STRING self.c_arg.value.string = self.value elif isinstance(value, int): self.value = int(value) self.c_arg.type = grpc.GRPC_ARG_INTEGER self.c_arg.value.integer = self.value else: raise TypeError("expected value to be of type str or bytes or int") self.c_arg.key = self.key cdef class ChannelArgs: def __cinit__(self, args): self.args = list(args) for arg in self.args: if not isinstance(arg, ChannelArg): raise TypeError("expected list of ChannelArg") self.c_args.arguments_length = len(self.args) self.c_args.arguments = grpc.gpr_malloc( self.c_args.arguments_length*sizeof(grpc.grpc_arg) ) for i in range(self.c_args.arguments_length): self.c_args.arguments[i] = (self.args[i]).c_arg def __dealloc__(self): grpc.gpr_free(self.c_args.arguments) def __len__(self): # self.args is never stale; it's only updated from this file return len(self.args) def __getitem__(self, size_t i): # self.args is never stale; it's only updated from this file return self.args[i] cdef class Metadatum: def __cinit__(self, key, value): if isinstance(key, bytes): self._key = key elif isinstance(key, basestring): self._key = key.encode() else: raise TypeError("expected key to be of type str or bytes") if isinstance(value, bytes): self._value = value elif isinstance(value, basestring): self._value = value.encode() else: raise TypeError("expected value to be of type str or bytes") self.c_metadata.key = self._key self.c_metadata.value = self._value self.c_metadata.value_length = len(self._value) @property def key(self): return self.c_metadata.key @property def value(self): return self.c_metadata.value[:self.c_metadata.value_length] def __len__(self): return 2 def __getitem__(self, size_t i): if i == 0: return self.key elif i == 1: return self.value else: raise IndexError("index must be 0 (key) or 1 (value)") def __iter__(self): return iter((self.key, self.value)) cdef class _MetadataIterator: cdef size_t i cdef Metadata metadata def __cinit__(self, Metadata metadata not None): self.i = 0 self.metadata = metadata def __next__(self): if self.i < len(self.metadata): result = self.metadata[self.i] self.i = self.i + 1 return result else: raise StopIteration() cdef class Metadata: def __cinit__(self, metadata): self.metadata = list(metadata) for metadatum in metadata: if not isinstance(metadatum, Metadatum): raise TypeError("expected list of Metadatum") grpc.grpc_metadata_array_init(&self.c_metadata_array) self.c_metadata_array.count = len(self.metadata) self.c_metadata_array.capacity = len(self.metadata) self.c_metadata_array.metadata = grpc.gpr_malloc( self.c_metadata_array.count*sizeof(grpc.grpc_metadata) ) for i in range(self.c_metadata_array.count): self.c_metadata_array.metadata[i] = ( (self.metadata[i]).c_metadata) def __dealloc__(self): # this frees the allocated memory for the grpc_metadata_array (although # it'd be nice if that were documented somewhere...) TODO(atash): document # this in the C core grpc.grpc_metadata_array_destroy(&self.c_metadata_array) def __len__(self): return self.c_metadata_array.count def __getitem__(self, size_t i): return Metadatum( key=self.c_metadata_array.metadata[i].key, value=self.c_metadata_array.metadata[i].value[ :self.c_metadata_array.metadata[i].value_length]) def __iter__(self): return _MetadataIterator(self) cdef class Operation: def __cinit__(self): self.references = [] self._received_status_details = NULL self._received_status_details_capacity = 0 self.is_valid = False @property def type(self): return self.c_op.type @property def received_message(self): if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE: raise TypeError("self must be an operation receiving a message") return self._received_message @property def received_metadata(self): if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT): raise TypeError("self must be an operation receiving metadata") return self._received_metadata @property def received_status_code(self): if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: raise TypeError("self must be an operation receiving a status code") return self._received_status_code @property def received_status_details(self): if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: raise TypeError("self must be an operation receiving status details") if self._received_status_details: return self._received_status_details else: return None @property def received_cancelled(self): if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER: raise TypeError("self must be an operation receiving cancellation " "information") return False if self._received_cancelled == 0 else True def __dealloc__(self): # We *almost* don't need to do anything; most of the objects are handled by # Python. The remaining one(s) are primitive fields filled in by GRPC core. # This means that we need to clean up after receive_status_on_client. if self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT: grpc.gpr_free(self._received_status_details) def operation_send_initial_metadata(Metadata metadata): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_SEND_INITIAL_METADATA op.c_op.data.send_initial_metadata.count = metadata.c_metadata_array.count op.c_op.data.send_initial_metadata.metadata = ( metadata.c_metadata_array.metadata) op.references.append(metadata) op.is_valid = True return op def operation_send_message(data): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_SEND_MESSAGE byte_buffer = ByteBuffer(data) op.c_op.data.send_message = byte_buffer.c_byte_buffer op.references.append(byte_buffer) op.is_valid = True return op def operation_send_close_from_client(): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT op.is_valid = True return op def operation_send_status_from_server( Metadata metadata, grpc.grpc_status_code code, details): if isinstance(details, bytes): pass elif isinstance(details, basestring): details = details.encode() else: raise TypeError("expected a str or bytes object for details") cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER op.c_op.data.send_status_from_server.trailing_metadata_count = ( metadata.c_metadata_array.count) op.c_op.data.send_status_from_server.trailing_metadata = ( metadata.c_metadata_array.metadata) op.c_op.data.send_status_from_server.status = code op.c_op.data.send_status_from_server.status_details = details op.references.append(metadata) op.references.append(details) op.is_valid = True return op def operation_receive_initial_metadata(): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_RECV_INITIAL_METADATA op._received_metadata = Metadata([]) op.c_op.data.receive_initial_metadata = ( &op._received_metadata.c_metadata_array) op.is_valid = True return op def operation_receive_message(): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_RECV_MESSAGE op._received_message = ByteBuffer(None) # n.b. the c_op.data.receive_message field needs to be deleted by us, # anyway, so we just let that be handled by the ByteBuffer() we allocated # the line before. op.c_op.data.receive_message = &op._received_message.c_byte_buffer op.is_valid = True return op def operation_receive_status_on_client(): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT op._received_metadata = Metadata([]) op.c_op.data.receive_status_on_client.trailing_metadata = ( &op._received_metadata.c_metadata_array) op.c_op.data.receive_status_on_client.status = ( &op._received_status_code) op.c_op.data.receive_status_on_client.status_details = ( &op._received_status_details) op.c_op.data.receive_status_on_client.status_details_capacity = ( &op._received_status_details_capacity) op.is_valid = True return op def operation_receive_close_on_server(): cdef Operation op = Operation() op.c_op.type = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER op.c_op.data.receive_close_on_server.cancelled = &op._received_cancelled op.is_valid = True return op cdef class _OperationsIterator: cdef size_t i cdef Operations operations def __cinit__(self, Operations operations not None): self.i = 0 self.operations = operations def __next__(self): if self.i < len(self.operations): result = self.operations[self.i] self.i = self.i + 1 return result else: raise StopIteration() cdef class Operations: def __cinit__(self, operations): self.operations = list(operations) # normalize iterable self.c_ops = NULL self.c_nops = 0 for operation in self.operations: if not isinstance(operation, Operation): raise TypeError("expected operations to be iterable of Operation") self.c_nops = len(self.operations) self.c_ops = grpc.gpr_malloc( sizeof(grpc.grpc_op)*self.c_nops) for i in range(self.c_nops): self.c_ops[i] = ((self.operations[i])).c_op def __len__(self): return self.c_nops def __getitem__(self, size_t i): # self.operations is never stale; it's only updated from this file return self.operations[i] def __dealloc__(self): grpc.gpr_free(self.c_ops) def __iter__(self): return _OperationsIterator(self) grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx0000644000175000017500000001114012600663151026452 0ustar apollockapollock# 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. cimport cpython from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport records import threading import time cdef class CompletionQueue: def __cinit__(self): self.c_completion_queue = grpc.grpc_completion_queue_create() self.is_shutting_down = False self.is_shutdown = False self.poll_condition = threading.Condition() self.is_polling = False def poll(self, records.Timespec deadline=None): # We name this 'poll' to avoid problems with CPython's expectations for # 'special' methods (like next and __next__). cdef grpc.gpr_timespec c_deadline = grpc.gpr_inf_future cdef records.OperationTag tag = None cdef object user_tag = None cdef call.Call operation_call = None cdef records.CallDetails request_call_details = None cdef records.Metadata request_metadata = None cdef records.Operations batch_operations = None if deadline is not None: c_deadline = deadline.c_time cdef grpc.grpc_event event # Poll within a critical section with self.poll_condition: while self.is_polling: self.poll_condition.wait(float(deadline) - time.time()) self.is_polling = True with nogil: event = grpc.grpc_completion_queue_next( self.c_completion_queue, c_deadline) with self.poll_condition: self.is_polling = False self.poll_condition.notify() if event.type == grpc.GRPC_QUEUE_TIMEOUT: return records.Event(event.type, False, None, None, None, None, None) elif event.type == grpc.GRPC_QUEUE_SHUTDOWN: self.is_shutdown = True return records.Event(event.type, True, None, None, None, None, None) else: if event.tag != NULL: tag = event.tag # We receive event tags only after they've been inc-ref'd elsewhere in # the code. cpython.Py_DECREF(tag) if tag.shutting_down_server is not None: tag.shutting_down_server.notify_shutdown_complete() user_tag = tag.user_tag operation_call = tag.operation_call request_call_details = tag.request_call_details request_metadata = tag.request_metadata batch_operations = tag.batch_operations if tag.is_new_request: # Stuff in the tag not explicitly handled by us needs to live through # the life of the call operation_call.references.extend(tag.references) return records.Event( event.type, event.success, user_tag, operation_call, request_call_details, request_metadata, batch_operations) def shutdown(self): grpc.grpc_completion_queue_shutdown(self.c_completion_queue) self.is_shutting_down = True def clear(self): if not self.is_shutting_down: raise ValueError('queue must be shutting down to be cleared') while self.poll().type != grpc.GRPC_QUEUE_SHUTDOWN: pass def __dealloc__(self): if self.c_completion_queue != NULL: # Ensure shutdown, pump the queue if not self.is_shutting_down: self.shutdown() while not self.is_shutdown: self.poll() grpc.grpc_completion_queue_destroy(self.c_completion_queue) grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx0000644000175000017500000001461512600663151024415 0ustar apollockapollock# 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. cimport cpython from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport completion_queue from grpc._cython._cygrpc cimport credentials from grpc._cython._cygrpc cimport records import time cdef class Server: def __cinit__(self, records.ChannelArgs arguments=None): cdef grpc.grpc_channel_args *c_arguments = NULL self.references = [] self.registered_completion_queues = [] if arguments is not None: c_arguments = &arguments.c_args self.references.append(arguments) self.c_server = grpc.grpc_server_create(c_arguments) self.is_started = False self.is_shutting_down = False self.is_shutdown = False def request_call( self, completion_queue.CompletionQueue call_queue not None, completion_queue.CompletionQueue server_queue not None, tag): if not self.is_started or self.is_shutting_down: raise ValueError("server must be started and not shutting down") if server_queue not in self.registered_completion_queues: raise ValueError("server_queue must be a registered completion queue") cdef records.OperationTag operation_tag = records.OperationTag(tag) operation_tag.operation_call = call.Call() operation_tag.request_call_details = records.CallDetails() operation_tag.request_metadata = records.Metadata([]) operation_tag.references.extend([self, call_queue, server_queue]) operation_tag.is_new_request = True operation_tag.batch_operations = records.Operations([]) cpython.Py_INCREF(operation_tag) return grpc.grpc_server_request_call( self.c_server, &operation_tag.operation_call.c_call, &operation_tag.request_call_details.c_details, &operation_tag.request_metadata.c_metadata_array, call_queue.c_completion_queue, server_queue.c_completion_queue, operation_tag) def register_completion_queue( self, completion_queue.CompletionQueue queue not None): if self.is_started: raise ValueError("cannot register completion queues after start") grpc.grpc_server_register_completion_queue( self.c_server, queue.c_completion_queue) self.registered_completion_queues.append(queue) def start(self): if self.is_started: raise ValueError("the server has already started") self.backup_shutdown_queue = completion_queue.CompletionQueue() self.register_completion_queue(self.backup_shutdown_queue) self.is_started = True grpc.grpc_server_start(self.c_server) def add_http2_port(self, address, credentials.ServerCredentials server_credentials=None): if isinstance(address, bytes): pass elif isinstance(address, basestring): address = address.encode() else: raise TypeError("expected address to be a str or bytes") self.references.append(address) if server_credentials is not None: self.references.append(server_credentials) return grpc.grpc_server_add_secure_http2_port( self.c_server, address, server_credentials.c_credentials) else: return grpc.grpc_server_add_http2_port(self.c_server, address) def shutdown(self, completion_queue.CompletionQueue queue not None, tag): cdef records.OperationTag operation_tag if queue.is_shutting_down: raise ValueError("queue must be live") elif not self.is_started: raise ValueError("the server hasn't started yet") elif self.is_shutting_down: return elif queue not in self.registered_completion_queues: raise ValueError("expected registered completion queue") else: self.is_shutting_down = True operation_tag = records.OperationTag(tag) operation_tag.shutting_down_server = self operation_tag.references.extend([self, queue]) cpython.Py_INCREF(operation_tag) grpc.grpc_server_shutdown_and_notify( self.c_server, queue.c_completion_queue, operation_tag) cdef notify_shutdown_complete(self): # called only by a completion queue on receiving our shutdown operation tag self.is_shutdown = True def cancel_all_calls(self): if not self.is_shutting_down: raise ValueError("the server must be shutting down to cancel all calls") elif self.is_shutdown: return else: grpc.grpc_server_cancel_all_calls(self.c_server) def __dealloc__(self): if self.c_server != NULL: if not self.is_started: pass elif self.is_shutdown: pass elif not self.is_shutting_down: # the user didn't call shutdown - use our backup queue self.shutdown(self.backup_shutdown_queue, None) # and now we wait while not self.is_shutdown: self.backup_shutdown_queue.poll() else: # We're in the process of shutting down, but have not shutdown; can't do # much but repeatedly release the GIL and wait while not self.is_shutdown: time.sleep(0) grpc.grpc_server_destroy(self.c_server) grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd0000644000175000017500000002764412600663151024023 0ustar apollockapollock# 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. cimport libc.time cdef extern from "grpc/support/alloc.h": void *gpr_malloc(size_t size) void gpr_free(void *ptr) void *gpr_realloc(void *p, size_t size) cdef extern from "grpc/support/slice.h": ctypedef struct gpr_slice: # don't worry about writing out the members of gpr_slice; we never access # them directly. pass gpr_slice gpr_slice_ref(gpr_slice s) void gpr_slice_unref(gpr_slice s) gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) gpr_slice gpr_slice_new_with_len( void *p, size_t len, void (*destroy)(void *, size_t)) gpr_slice gpr_slice_malloc(size_t length) gpr_slice gpr_slice_from_copied_string(const char *source) gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len) # Declare functions for function-like macros (because Cython)... void *gpr_slice_start_ptr "GPR_SLICE_START_PTR" (gpr_slice s) size_t gpr_slice_length "GPR_SLICE_LENGTH" (gpr_slice s) cdef extern from "grpc/support/port_platform.h": # As long as the header file gets this type right, we don't need to get this # type exactly; just close enough that the operations will be supported in the # underlying C layers. ctypedef unsigned int gpr_uint32 cdef extern from "grpc/support/time.h": ctypedef struct gpr_timespec: libc.time.time_t seconds "tv_sec" int nanoseconds "tv_nsec" cdef gpr_timespec gpr_time_0 cdef gpr_timespec gpr_inf_future cdef gpr_timespec gpr_inf_past gpr_timespec gpr_now() cdef extern from "grpc/status.h": ctypedef enum grpc_status_code: GRPC_STATUS_OK GRPC_STATUS_CANCELLED GRPC_STATUS_UNKNOWN GRPC_STATUS_INVALID_ARGUMENT GRPC_STATUS_DEADLINE_EXCEEDED GRPC_STATUS_NOT_FOUND GRPC_STATUS_ALREADY_EXISTS GRPC_STATUS_PERMISSION_DENIED GRPC_STATUS_UNAUTHENTICATED GRPC_STATUS_RESOURCE_EXHAUSTED GRPC_STATUS_FAILED_PRECONDITION GRPC_STATUS_ABORTED GRPC_STATUS_OUT_OF_RANGE GRPC_STATUS_UNIMPLEMENTED GRPC_STATUS_INTERNAL GRPC_STATUS_UNAVAILABLE GRPC_STATUS_DATA_LOSS GRPC_STATUS__DO_NOT_USE cdef extern from "grpc/byte_buffer_reader.h": struct grpc_byte_buffer_reader: # We don't care about the internals pass cdef extern from "grpc/byte_buffer.h": ctypedef struct grpc_byte_buffer: # We don't care about the internals. pass grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices, size_t nslices) size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer) void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, grpc_byte_buffer *buffer) int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, gpr_slice *slice) void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) cdef extern from "grpc/grpc.h": ctypedef struct grpc_completion_queue: # We don't care about the internals (and in fact don't know them) pass ctypedef struct grpc_channel: # We don't care about the internals (and in fact don't know them) pass ctypedef struct grpc_server: # We don't care about the internals (and in fact don't know them) pass ctypedef struct grpc_call: # We don't care about the internals (and in fact don't know them) pass ctypedef enum grpc_arg_type: grpc_arg_string "GRPC_ARG_STRING" grpc_arg_integer "GRPC_ARG_INTEGER" grpc_arg_pointer "GRPC_ARG_POINTER" ctypedef struct grpc_arg_value_pointer: void *address "p" void *(*copy)(void *) void (*destroy)(void *) union grpc_arg_value: char *string int integer grpc_arg_value_pointer pointer ctypedef struct grpc_arg: grpc_arg_type type char *key grpc_arg_value value ctypedef struct grpc_channel_args: size_t arguments_length "num_args" grpc_arg *arguments "args" ctypedef enum grpc_call_error: GRPC_CALL_OK GRPC_CALL_ERROR GRPC_CALL_ERROR_NOT_ON_SERVER GRPC_CALL_ERROR_NOT_ON_CLIENT GRPC_CALL_ERROR_ALREADY_ACCEPTED GRPC_CALL_ERROR_ALREADY_INVOKED GRPC_CALL_ERROR_NOT_INVOKED GRPC_CALL_ERROR_ALREADY_FINISHED GRPC_CALL_ERROR_TOO_MANY_OPERATIONS GRPC_CALL_ERROR_INVALID_FLAGS GRPC_CALL_ERROR_INVALID_METADATA ctypedef struct grpc_metadata: const char *key const char *value size_t value_length # ignore the 'internal_data.obfuscated' fields. ctypedef enum grpc_completion_type: GRPC_QUEUE_SHUTDOWN GRPC_QUEUE_TIMEOUT GRPC_OP_COMPLETE ctypedef struct grpc_event: grpc_completion_type type int success void *tag ctypedef struct grpc_metadata_array: size_t count size_t capacity grpc_metadata *metadata void grpc_metadata_array_init(grpc_metadata_array *array) void grpc_metadata_array_destroy(grpc_metadata_array *array) ctypedef struct grpc_call_details: char *method size_t method_capacity char *host size_t host_capacity gpr_timespec deadline void grpc_call_details_init(grpc_call_details *details) void grpc_call_details_destroy(grpc_call_details *details) ctypedef enum grpc_op_type: GRPC_OP_SEND_INITIAL_METADATA GRPC_OP_SEND_MESSAGE GRPC_OP_SEND_CLOSE_FROM_CLIENT GRPC_OP_SEND_STATUS_FROM_SERVER GRPC_OP_RECV_INITIAL_METADATA GRPC_OP_RECV_MESSAGE GRPC_OP_RECV_STATUS_ON_CLIENT GRPC_OP_RECV_CLOSE_ON_SERVER ctypedef struct grpc_op_data_send_initial_metadata: size_t count grpc_metadata *metadata ctypedef struct grpc_op_data_send_status_from_server: size_t trailing_metadata_count grpc_metadata *trailing_metadata grpc_status_code status const char *status_details ctypedef struct grpc_op_data_recv_status_on_client: grpc_metadata_array *trailing_metadata grpc_status_code *status char **status_details size_t *status_details_capacity ctypedef struct grpc_op_data_recv_close_on_server: int *cancelled union grpc_op_data: grpc_op_data_send_initial_metadata send_initial_metadata grpc_byte_buffer *send_message grpc_op_data_send_status_from_server send_status_from_server grpc_metadata_array *receive_initial_metadata "recv_initial_metadata" grpc_byte_buffer **receive_message "recv_message" grpc_op_data_recv_status_on_client receive_status_on_client "recv_status_on_client" grpc_op_data_recv_close_on_server receive_close_on_server "recv_close_on_server" ctypedef struct grpc_op: grpc_op_type type "op" gpr_uint32 flags grpc_op_data data void grpc_init() void grpc_shutdown() grpc_completion_queue *grpc_completion_queue_create() grpc_event grpc_completion_queue_next(grpc_completion_queue *cq, gpr_timespec deadline) nogil void grpc_completion_queue_shutdown(grpc_completion_queue *cq) void grpc_completion_queue_destroy(grpc_completion_queue *cq) grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, size_t nops, void *tag) grpc_call_error grpc_call_cancel(grpc_call *call) grpc_call_error grpc_call_cancel_with_status(grpc_call *call, grpc_status_code status, const char *description) void grpc_call_destroy(grpc_call *call) grpc_channel *grpc_channel_create(const char *target, const grpc_channel_args *args) grpc_call *grpc_channel_create_call(grpc_channel *channel, grpc_completion_queue *completion_queue, const char *method, const char *host, gpr_timespec deadline) void grpc_channel_destroy(grpc_channel *channel) grpc_server *grpc_server_create(const grpc_channel_args *args) grpc_call_error grpc_server_request_call( grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *request_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new) void grpc_server_register_completion_queue(grpc_server *server, grpc_completion_queue *cq) int grpc_server_add_http2_port(grpc_server *server, const char *addr) void grpc_server_start(grpc_server *server) void grpc_server_shutdown_and_notify( grpc_server *server, grpc_completion_queue *cq, void *tag) void grpc_server_cancel_all_calls(grpc_server *server) void grpc_server_destroy(grpc_server *server) cdef extern from "grpc/grpc_security.h": ctypedef struct grpc_ssl_pem_key_cert_pair: const char *private_key const char *certificate_chain "cert_chain" ctypedef struct grpc_credentials: # We don't care about the internals (and in fact don't know them) pass grpc_credentials *grpc_google_default_credentials_create() grpc_credentials *grpc_ssl_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair) grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, grpc_credentials *creds2) grpc_credentials *grpc_compute_engine_credentials_create() grpc_credentials *grpc_service_account_jwt_access_credentials_create(const char *json_key, gpr_timespec token_lifetime) grpc_credentials *grpc_refresh_token_credentials_create( const char *json_refresh_token) grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, const char *authority_selector) void grpc_credentials_release(grpc_credentials *creds) grpc_channel *grpc_secure_channel_create( grpc_credentials *creds, const char *target, const grpc_channel_args *args) ctypedef struct grpc_server_credentials: # We don't care about the internals (and in fact don't know them) pass grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs) void grpc_server_credentials_release(grpc_server_credentials *creds) int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_credentials *creds) grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/__init__.py0000644000175000017500000000277012600663151024455 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/server.pxd0000644000175000017500000000402112600663151024356 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport completion_queue cdef class Server: cdef grpc.grpc_server *c_server cdef bint is_started # start has been called cdef bint is_shutting_down # shutdown has been called cdef bint is_shutdown # notification of complete shutdown received # used at dealloc when user forgets to shutdown cdef completion_queue.CompletionQueue backup_shutdown_queue cdef list references cdef list registered_completion_queues cdef notify_shutdown_complete(self) grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd0000644000175000017500000000333612600663151026435 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc cdef class CompletionQueue: cdef grpc.grpc_completion_queue *c_completion_queue cdef object poll_condition cdef bint is_polling cdef bint is_shutting_down cdef bint is_shutdown grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd0000644000175000017500000000363412600663151025356 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc cdef class ClientCredentials: cdef grpc.grpc_credentials *c_credentials cdef grpc.grpc_ssl_pem_key_cert_pair c_ssl_pem_key_cert_pair cdef list references cdef class ServerCredentials: cdef grpc.grpc_server_credentials *c_credentials cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs cdef size_t c_ssl_pem_key_cert_pairs_count cdef list references grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/call.pxd0000644000175000017500000000315212600663151023767 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport grpc cdef class Call: cdef grpc.grpc_call *c_call cdef list references grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx0000644000175000017500000001705012600663151025400 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport records cdef class ClientCredentials: def __cinit__(self): self.c_credentials = NULL self.c_ssl_pem_key_cert_pair.private_key = NULL self.c_ssl_pem_key_cert_pair.certificate_chain = NULL self.references = [] # The object *can* be invalid in Python if we fail to make the credentials # (and the core thus returns NULL credentials). Used primarily for debugging. @property def is_valid(self): return self.c_credentials != NULL def __dealloc__(self): if self.c_credentials != NULL: grpc.grpc_credentials_release(self.c_credentials) cdef class ServerCredentials: def __cinit__(self): self.c_credentials = NULL def __dealloc__(self): if self.c_credentials != NULL: grpc.grpc_server_credentials_release(self.c_credentials) def client_credentials_google_default(): cdef ClientCredentials credentials = ClientCredentials(); credentials.c_credentials = grpc.grpc_google_default_credentials_create() return credentials def client_credentials_ssl(pem_root_certificates, records.SslPemKeyCertPair ssl_pem_key_cert_pair): if pem_root_certificates is None: pass elif isinstance(pem_root_certificates, bytes): pass elif isinstance(pem_root_certificates, basestring): pem_root_certificates = pem_root_certificates.encode() else: raise TypeError("expected str or bytes for pem_root_certificates") cdef ClientCredentials credentials = ClientCredentials() cdef const char *c_pem_root_certificates = NULL if pem_root_certificates is not None: c_pem_root_certificates = pem_root_certificates credentials.references.append(pem_root_certificates) if ssl_pem_key_cert_pair is not None: credentials.c_credentials = grpc.grpc_ssl_credentials_create( c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair ) credentials.references.append(ssl_pem_key_cert_pair) else: credentials.c_credentials = grpc.grpc_ssl_credentials_create( c_pem_root_certificates, NULL ) def client_credentials_composite_credentials( ClientCredentials credentials_1 not None, ClientCredentials credentials_2 not None): if not credentials_1.is_valid or not credentials_2.is_valid: raise ValueError("passed credentials must both be valid") cdef ClientCredentials credentials = ClientCredentials() credentials.c_credentials = grpc.grpc_composite_credentials_create( credentials_1.c_credentials, credentials_2.c_credentials) credentials.references.append(credentials_1) credentials.references.append(credentials_2) return credentials def client_credentials_compute_engine(): cdef ClientCredentials credentials = ClientCredentials() credentials.c_credentials = grpc.grpc_compute_engine_credentials_create() return credentials #TODO rename to something like client_credentials_service_account_jwt_access. def client_credentials_jwt(json_key, records.Timespec token_lifetime not None): if isinstance(json_key, bytes): pass elif isinstance(json_key, basestring): json_key = json_key.encode() else: raise TypeError("expected json_key to be str or bytes") cdef ClientCredentials credentials = ClientCredentials() credentials.c_credentials = grpc.grpc_service_account_jwt_access_credentials_create( json_key, token_lifetime.c_time) credentials.references.append(json_key) return credentials def client_credentials_refresh_token(json_refresh_token): if isinstance(json_refresh_token, bytes): pass elif isinstance(json_refresh_token, basestring): json_refresh_token = json_refresh_token.encode() else: raise TypeError("expected json_refresh_token to be str or bytes") cdef ClientCredentials credentials = ClientCredentials() credentials.c_credentials = grpc.grpc_refresh_token_credentials_create( json_refresh_token) credentials.references.append(json_refresh_token) return credentials def client_credentials_iam(authorization_token, authority_selector): if isinstance(authorization_token, bytes): pass elif isinstance(authorization_token, basestring): authorization_token = authorization_token.encode() else: raise TypeError("expected authorization_token to be str or bytes") if isinstance(authority_selector, bytes): pass elif isinstance(authority_selector, basestring): authority_selector = authority_selector.encode() else: raise TypeError("expected authority_selector to be str or bytes") cdef ClientCredentials credentials = ClientCredentials() credentials.c_credentials = grpc.grpc_iam_credentials_create( authorization_token, authority_selector) credentials.references.append(authorization_token) credentials.references.append(authority_selector) return credentials def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs): if pem_root_certs is None: pass elif isinstance(pem_root_certs, bytes): pass elif isinstance(pem_root_certs, basestring): pem_root_certs = pem_root_certs.encode() else: raise TypeError("expected pem_root_certs to be str or bytes") pem_key_cert_pairs = list(pem_key_cert_pairs) for pair in pem_key_cert_pairs: if not isinstance(pair, records.SslPemKeyCertPair): raise TypeError("expected pem_key_cert_pairs to be sequence of " "records.SslPemKeyCertPair") cdef ServerCredentials credentials = ServerCredentials() credentials.references.append(pem_key_cert_pairs) credentials.references.append(pem_root_certs) credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) credentials.c_ssl_pem_key_cert_pairs = ( grpc.gpr_malloc( sizeof(grpc.grpc_ssl_pem_key_cert_pair) * credentials.c_ssl_pem_key_cert_pairs_count )) for i in range(credentials.c_ssl_pem_key_cert_pairs_count): credentials.c_ssl_pem_key_cert_pairs[i] = ( (pem_key_cert_pairs[i]).c_pair) credentials.c_credentials = grpc.grpc_ssl_server_credentials_create( pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, credentials.c_ssl_pem_key_cert_pairs_count ) return credentials grpc-0.11.1/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx0000644000175000017500000000676212600663151024523 0ustar apollockapollock# 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. from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport completion_queue from grpc._cython._cygrpc cimport credentials from grpc._cython._cygrpc cimport records cdef class Channel: def __cinit__(self, target, records.ChannelArgs arguments=None, credentials.ClientCredentials client_credentials=None): cdef grpc.grpc_channel_args *c_arguments = NULL self.c_channel = NULL self.references = [] if arguments is not None: c_arguments = &arguments.c_args if isinstance(target, bytes): pass elif isinstance(target, basestring): target = target.encode() else: raise TypeError("expected target to be str or bytes") if client_credentials is None: self.c_channel = grpc.grpc_channel_create(target, c_arguments) else: self.c_channel = grpc.grpc_secure_channel_create( client_credentials.c_credentials, target, c_arguments) self.references.append(client_credentials) self.references.append(target) self.references.append(arguments) def create_call(self, completion_queue.CompletionQueue queue not None, method, host, records.Timespec deadline not None): if queue.is_shutting_down: raise ValueError("queue must not be shutting down or shutdown") if isinstance(method, bytes): pass elif isinstance(method, basestring): method = method.encode() else: raise TypeError("expected method to be str or bytes") if isinstance(host, bytes): pass elif isinstance(host, basestring): host = host.encode() else: raise TypeError("expected host to be str or bytes") cdef call.Call operation_call = call.Call() operation_call.references = [self, method, host, queue] operation_call.c_call = grpc.grpc_channel_create_call( self.c_channel, queue.c_completion_queue, method, host, deadline.c_time) return operation_call def __dealloc__(self): if self.c_channel != NULL: grpc.grpc_channel_destroy(self.c_channel) grpc-0.11.1/src/python/grpcio/grpc/_cython/cygrpc.pyx0000644000175000017500000001011612600663151022740 0ustar apollockapollock# 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. cimport cpython from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport call from grpc._cython._cygrpc cimport channel from grpc._cython._cygrpc cimport credentials from grpc._cython._cygrpc cimport completion_queue from grpc._cython._cygrpc cimport records from grpc._cython._cygrpc cimport server from grpc._cython._cygrpc import call from grpc._cython._cygrpc import channel from grpc._cython._cygrpc import credentials from grpc._cython._cygrpc import completion_queue from grpc._cython._cygrpc import records from grpc._cython._cygrpc import server StatusCode = records.StatusCode CallError = records.CallError CompletionType = records.CompletionType OperationType = records.OperationType Timespec = records.Timespec CallDetails = records.CallDetails Event = records.Event ByteBuffer = records.ByteBuffer SslPemKeyCertPair = records.SslPemKeyCertPair ChannelArg = records.ChannelArg ChannelArgs = records.ChannelArgs Metadatum = records.Metadatum Metadata = records.Metadata Operation = records.Operation operation_send_initial_metadata = records.operation_send_initial_metadata operation_send_message = records.operation_send_message operation_send_close_from_client = records.operation_send_close_from_client operation_send_status_from_server = records.operation_send_status_from_server operation_receive_initial_metadata = records.operation_receive_initial_metadata operation_receive_message = records.operation_receive_message operation_receive_status_on_client = records.operation_receive_status_on_client operation_receive_close_on_server = records.operation_receive_close_on_server Operations = records.Operations ClientCredentials = credentials.ClientCredentials ServerCredentials = credentials.ServerCredentials client_credentials_google_default = ( credentials.client_credentials_google_default) client_credentials_ssl = credentials.client_credentials_ssl client_credentials_composite_credentials = ( credentials.client_credentials_composite_credentials) client_credentials_compute_engine = ( credentials.client_credentials_compute_engine) client_credentials_jwt = credentials.client_credentials_jwt client_credentials_refresh_token = credentials.client_credentials_refresh_token client_credentials_iam = credentials.client_credentials_iam server_credentials_ssl = credentials.server_credentials_ssl CompletionQueue = completion_queue.CompletionQueue Channel = channel.Channel Server = server.Server Call = call.Call # # Global state # cdef class _ModuleState: def __cinit__(self): grpc.grpc_init() def __dealloc__(self): grpc.grpc_shutdown() _module_state = _ModuleState() grpc-0.11.1/src/python/grpcio/grpc/_cython/README.rst0000644000175000017500000000430612600663151022402 0ustar apollockapollockGRPC Python Cython layer ======================== Package for the GRPC Python Cython layer. What is Cython? --------------- Cython is both a superset of the Python language with extensions for dealing with C types and a tool that transpiles this superset into C code. It provides convenient means of statically typing expressions and of converting Python strings to pointers (among other niceties), thus dramatically smoothing the Python/C interop by allowing fluid use of APIs in both from the same source. See the wonderful `Cython website`_. Why Cython? ----------- - **Python 2 and 3 support** Cython generated C code has precompiler macros to target both Python 2 and Python 3 C APIs, even while acting as a superset of just the Python 2 language (e.g. using ``basestring``). - **Significantly less semantic noise** A lot of CPython code is just glue, especially human-error-prone ``Py_INCREF``-ing and ``Py_DECREF``-ing around error handlers and such. Cython takes care of that automagically. - **Possible PyPy support** One of the major developments in Cython over the past few years was the addition of support for PyPy. We might soon be able to provide such support ourselves through our use of Cython. - **Less Python glue code** There existed several adapter layers in and around the original CPython code to smooth the surface exposed to Python due to how much trouble it was to make such a smooth surface via the CPython API alone. Cython makes writing such a surface incredibly easy, so these adapter layers may be removed. Implications for Users ---------------------- Nothing additional will be required for users. PyPI packages will contain Cython generated C code and thus not necessitate a Cython installation. Implications for GRPC Developers -------------------------------- A typical edit-compile-debug cycle now requires Cython. We install Cython in the ``virtualenv`` generated for the Python tests in this repository, so initial test runs may take an extra 2+ minutes to complete. Subsequent test runs won't reinstall ``Cython`` (unless required versions change and the ``virtualenv`` doesn't have installed versions that satisfy the change). .. _`Cython website`: http://cython.org/ grpc-0.11.1/src/python/grpcio/grpc/_cython/__init__.py0000644000175000017500000000277012600663151023027 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/_cython/adapter_low.py0000644000175000017500000000574712600663151023600 0ustar apollockapollock# 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. # Adapter from grpc._cython.types to the surface expected by # grpc._adapter._intermediary_low. # # TODO(atash): Once this is plugged into grpc._adapter._intermediary_low, remove # both grpc._adapter._intermediary_low and this file. The fore and rear links in # grpc._adapter should be able to use grpc._cython.types directly. from grpc._adapter import _types as type_interfaces from grpc._cython import cygrpc class ClientCredentials(object): def __init__(self): raise NotImplementedError() @staticmethod def google_default(): raise NotImplementedError() @staticmethod def ssl(): raise NotImplementedError() @staticmethod def composite(): raise NotImplementedError() @staticmethod def compute_engine(): raise NotImplementedError() @staticmethod def jwt(): raise NotImplementedError() @staticmethod def refresh_token(): raise NotImplementedError() @staticmethod def iam(): raise NotImplementedError() class ServerCredentials(object): def __init__(self): raise NotImplementedError() @staticmethod def ssl(): raise NotImplementedError() class CompletionQueue(type_interfaces.CompletionQueue): def __init__(self): raise NotImplementedError() class Call(type_interfaces.Call): def __init__(self): raise NotImplementedError() class Channel(type_interfaces.Channel): def __init__(self): raise NotImplementedError() class Server(type_interfaces.Server): def __init__(self): raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/_cython/.gitignore0000644000175000017500000000004312600663151022675 0ustar apollockapollock*.h *.c *.a *.so *.dll *.pyc *.pyd grpc-0.11.1/src/python/grpcio/grpc/early_adopter/0000755000175000017500000000000012600663151022077 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/early_adopter/implementations.py0000644000175000017500000002433612600663151025671 0ustar apollockapollock# 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. """Entry points into GRPC.""" import threading from grpc._adapter import fore as _fore from grpc._adapter import rear as _rear from grpc.framework.alpha import _face_utilities from grpc.framework.alpha import _reexport from grpc.framework.alpha import interfaces from grpc.framework.base import implementations as _base_implementations from grpc.framework.base import util as _base_utilities from grpc.framework.face import implementations as _face_implementations from grpc.framework.foundation import logging_pool _DEFAULT_THREAD_POOL_SIZE = 8 _ONE_DAY_IN_SECONDS = 24 * 60 * 60 class _Server(interfaces.Server): def __init__( self, breakdown, port, private_key, certificate_chain, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): self._lock = threading.Lock() self._breakdown = breakdown self._port = port if private_key is None or certificate_chain is None: self._key_chain_pairs = () else: self._key_chain_pairs = ((private_key, certificate_chain),) self._pool_size = thread_pool_size self._pool = None self._back = None self._fore_link = None def _start(self): with self._lock: if self._pool is None: self._pool = logging_pool.pool(self._pool_size) servicer = _face_implementations.servicer( self._pool, self._breakdown.implementations, None) self._back = _base_implementations.back_link( servicer, self._pool, self._pool, self._pool, _ONE_DAY_IN_SECONDS, _ONE_DAY_IN_SECONDS) self._fore_link = _fore.ForeLink( self._pool, self._breakdown.request_deserializers, self._breakdown.response_serializers, None, self._key_chain_pairs, port=self._port) self._back.join_fore_link(self._fore_link) self._fore_link.join_rear_link(self._back) self._fore_link.start() else: raise ValueError('Server currently running!') def _stop(self): with self._lock: if self._pool is None: raise ValueError('Server not running!') else: self._fore_link.stop() _base_utilities.wait_for_idle(self._back) self._pool.shutdown(wait=True) self._fore_link = None self._back = None self._pool = None def __enter__(self): self._start() return self def __exit__(self, exc_type, exc_val, exc_tb): self._stop() return False def start(self): self._start() def stop(self): self._stop() def port(self): with self._lock: return self._fore_link.port() class _Stub(interfaces.Stub): def __init__( self, breakdown, host, port, secure, root_certificates, private_key, certificate_chain, metadata_transformer=None, server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): self._lock = threading.Lock() self._breakdown = breakdown self._host = host self._port = port self._secure = secure self._root_certificates = root_certificates self._private_key = private_key self._certificate_chain = certificate_chain self._metadata_transformer = metadata_transformer self._server_host_override = server_host_override self._pool_size = thread_pool_size self._pool = None self._front = None self._rear_link = None self._understub = None def __enter__(self): with self._lock: if self._pool is None: self._pool = logging_pool.pool(self._pool_size) self._front = _base_implementations.front_link( self._pool, self._pool, self._pool) self._rear_link = _rear.RearLink( self._host, self._port, self._pool, self._breakdown.request_serializers, self._breakdown.response_deserializers, self._secure, self._root_certificates, self._private_key, self._certificate_chain, metadata_transformer=self._metadata_transformer, server_host_override=self._server_host_override) self._front.join_rear_link(self._rear_link) self._rear_link.join_fore_link(self._front) self._rear_link.start() self._understub = _face_implementations.dynamic_stub( self._breakdown.face_cardinalities, self._front, self._pool, '') else: raise ValueError('Tried to __enter__ already-__enter__ed Stub!') return self def __exit__(self, exc_type, exc_val, exc_tb): with self._lock: if self._pool is None: raise ValueError('Tried to __exit__ non-__enter__ed Stub!') else: self._rear_link.stop() _base_utilities.wait_for_idle(self._front) self._pool.shutdown(wait=True) self._rear_link = None self._front = None self._pool = None self._understub = None return False def __getattr__(self, attr): with self._lock: if self._pool is None: raise ValueError('Tried to __getattr__ non-__enter__ed Stub!') else: method_cardinality = self._breakdown.cardinalities.get(attr) underlying_attr = getattr( self._understub, self._breakdown.qualified_names.get(attr), None) if method_cardinality is interfaces.Cardinality.UNARY_UNARY: return _reexport.unary_unary_sync_async(underlying_attr) elif method_cardinality is interfaces.Cardinality.UNARY_STREAM: return lambda request, timeout: _reexport.cancellable_iterator( underlying_attr(request, timeout)) elif method_cardinality is interfaces.Cardinality.STREAM_UNARY: return _reexport.stream_unary_sync_async(underlying_attr) elif method_cardinality is interfaces.Cardinality.STREAM_STREAM: return lambda request_iterator, timeout: ( _reexport.cancellable_iterator(underlying_attr( request_iterator, timeout))) else: raise AttributeError(attr) def stub( service_name, methods, host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): """Constructs an interfaces.Stub. Args: service_name: The package-qualified full name of the service. methods: A dictionary from RPC method name to interfaces.RpcMethodInvocationDescription describing the RPCs to be supported by the created stub. The RPC method names in the dictionary are not qualified by the service name or decorated in any other way. host: The host to which to connect for RPC service. port: The port to which to connect for RPC service. metadata_transformer: A callable that given a metadata object produces another metadata object to be used in the underlying communication on the wire. secure: Whether or not to construct the stub with a secure connection. root_certificates: The PEM-encoded root certificates or None to ask for them to be retrieved from a default location. private_key: The PEM-encoded private key to use or None if no private key should be used. certificate_chain: The PEM-encoded certificate chain to use or None if no certificate chain should be used. server_host_override: (For testing only) the target name used for SSL host name checking. thread_pool_size: The maximum number of threads to allow in the backing thread pool. Returns: An interfaces.Stub affording RPC invocation. """ breakdown = _face_utilities.break_down_invocation(service_name, methods) return _Stub( breakdown, host, port, secure, root_certificates, private_key, certificate_chain, server_host_override=server_host_override, metadata_transformer=metadata_transformer, thread_pool_size=thread_pool_size) def server( service_name, methods, port, private_key=None, certificate_chain=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): """Constructs an interfaces.Server. Args: service_name: The package-qualified full name of the service. methods: A dictionary from RPC method name to interfaces.RpcMethodServiceDescription describing the RPCs to be serviced by the created server. The RPC method names in the dictionary are not qualified by the service name or decorated in any other way. port: The port on which to serve or zero to ask for a port to be automatically selected. private_key: A pem-encoded private key, or None for an insecure server. certificate_chain: A pem-encoded certificate chain, or None for an insecure server. thread_pool_size: The maximum number of threads to allow in the backing thread pool. Returns: An interfaces.Server that will serve secure traffic. """ breakdown = _face_utilities.break_down_service(service_name, methods) return _Server(breakdown, port, private_key, certificate_chain, thread_pool_size=thread_pool_size) grpc-0.11.1/src/python/grpcio/grpc/early_adopter/__init__.py0000644000175000017500000000277212600663151024220 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/0000755000175000017500000000000012600663151021242 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/alpha/0000755000175000017500000000000012600663151022327 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/alpha/exceptions.py0000644000175000017500000000361412600663151025066 0ustar apollockapollock# 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. """Exceptions raised by GRPC. Only GRPC should instantiate and raise these exceptions. """ import abc class RpcError(Exception): """Common super type for all exceptions raised by GRPC.""" __metaclass__ = abc.ABCMeta class CancellationError(RpcError): """Indicates that an RPC has been cancelled.""" class ExpirationError(RpcError): """Indicates that an RPC has expired ("timed out").""" grpc-0.11.1/src/python/grpcio/grpc/framework/alpha/utilities.py0000644000175000017500000002536212600663151024724 0ustar apollockapollock# 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. """Utilities for use with GRPC.""" from grpc.framework.alpha import interfaces class _RpcMethodDescription( interfaces.RpcMethodInvocationDescription, interfaces.RpcMethodServiceDescription): def __init__( self, cardinality, unary_unary, unary_stream, stream_unary, stream_stream, request_serializer, request_deserializer, response_serializer, response_deserializer): self._cardinality = cardinality self._unary_unary = unary_unary self._unary_stream = unary_stream self._stream_unary = stream_unary self._stream_stream = stream_stream self._request_serializer = request_serializer self._request_deserializer = request_deserializer self._response_serializer = response_serializer self._response_deserializer = response_deserializer def cardinality(self): """See interfaces.RpcMethodDescription.cardinality for specification.""" return self._cardinality def serialize_request(self, request): """See interfaces.RpcMethodInvocationDescription.serialize_request.""" return self._request_serializer(request) def deserialize_request(self, serialized_request): """See interfaces.RpcMethodServiceDescription.deserialize_request.""" return self._request_deserializer(serialized_request) def serialize_response(self, response): """See interfaces.RpcMethodServiceDescription.serialize_response.""" return self._response_serializer(response) def deserialize_response(self, serialized_response): """See interfaces.RpcMethodInvocationDescription.deserialize_response.""" return self._response_deserializer(serialized_response) def service_unary_unary(self, request, context): """See interfaces.RpcMethodServiceDescription.service_unary_unary.""" return self._unary_unary(request, context) def service_unary_stream(self, request, context): """See interfaces.RpcMethodServiceDescription.service_unary_stream.""" return self._unary_stream(request, context) def service_stream_unary(self, request_iterator, context): """See interfaces.RpcMethodServiceDescription.service_stream_unary.""" return self._stream_unary(request_iterator, context) def service_stream_stream(self, request_iterator, context): """See interfaces.RpcMethodServiceDescription.service_stream_stream.""" return self._stream_stream(request_iterator, context) def unary_unary_invocation_description( request_serializer, response_deserializer): """Creates an interfaces.RpcMethodInvocationDescription for an RPC method. Args: request_serializer: A callable that when called on a request value returns a bytestring corresponding to that value. response_deserializer: A callable that when called on a bytestring returns the response value corresponding to that bytestring. Returns: An interfaces.RpcMethodInvocationDescription constructed from the given arguments representing a unary-request/unary-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.UNARY_UNARY, None, None, None, None, request_serializer, None, None, response_deserializer) def unary_stream_invocation_description( request_serializer, response_deserializer): """Creates an interfaces.RpcMethodInvocationDescription for an RPC method. Args: request_serializer: A callable that when called on a request value returns a bytestring corresponding to that value. response_deserializer: A callable that when called on a bytestring returns the response value corresponding to that bytestring. Returns: An interfaces.RpcMethodInvocationDescription constructed from the given arguments representing a unary-request/streaming-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.UNARY_STREAM, None, None, None, None, request_serializer, None, None, response_deserializer) def stream_unary_invocation_description( request_serializer, response_deserializer): """Creates an interfaces.RpcMethodInvocationDescription for an RPC method. Args: request_serializer: A callable that when called on a request value returns a bytestring corresponding to that value. response_deserializer: A callable that when called on a bytestring returns the response value corresponding to that bytestring. Returns: An interfaces.RpcMethodInvocationDescription constructed from the given arguments representing a streaming-request/unary-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.STREAM_UNARY, None, None, None, None, request_serializer, None, None, response_deserializer) def stream_stream_invocation_description( request_serializer, response_deserializer): """Creates an interfaces.RpcMethodInvocationDescription for an RPC method. Args: request_serializer: A callable that when called on a request value returns a bytestring corresponding to that value. response_deserializer: A callable that when called on a bytestring returns the response value corresponding to that bytestring. Returns: An interfaces.RpcMethodInvocationDescription constructed from the given arguments representing a streaming-request/streaming-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.STREAM_STREAM, None, None, None, None, request_serializer, None, None, response_deserializer) def unary_unary_service_description( behavior, request_deserializer, response_serializer): """Creates an interfaces.RpcMethodServiceDescription for the given behavior. Args: behavior: A callable that implements a unary-unary RPC method that accepts a single request and an interfaces.RpcContext and returns a single response. request_deserializer: A callable that when called on a bytestring returns the request value corresponding to that bytestring. response_serializer: A callable that when called on a response value returns the bytestring corresponding to that value. Returns: An interfaces.RpcMethodServiceDescription constructed from the given arguments representing a unary-request/unary-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.UNARY_UNARY, behavior, None, None, None, None, request_deserializer, response_serializer, None) def unary_stream_service_description( behavior, request_deserializer, response_serializer): """Creates an interfaces.RpcMethodServiceDescription for the given behavior. Args: behavior: A callable that implements a unary-stream RPC method that accepts a single request and an interfaces.RpcContext and returns an iterator of zero or more responses. request_deserializer: A callable that when called on a bytestring returns the request value corresponding to that bytestring. response_serializer: A callable that when called on a response value returns the bytestring corresponding to that value. Returns: An interfaces.RpcMethodServiceDescription constructed from the given arguments representing a unary-request/streaming-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.UNARY_STREAM, None, behavior, None, None, None, request_deserializer, response_serializer, None) def stream_unary_service_description( behavior, request_deserializer, response_serializer): """Creates an interfaces.RpcMethodServiceDescription for the given behavior. Args: behavior: A callable that implements a stream-unary RPC method that accepts an iterator of zero or more requests and an interfaces.RpcContext and returns a single response. request_deserializer: A callable that when called on a bytestring returns the request value corresponding to that bytestring. response_serializer: A callable that when called on a response value returns the bytestring corresponding to that value. Returns: An interfaces.RpcMethodServiceDescription constructed from the given arguments representing a streaming-request/unary-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.STREAM_UNARY, None, None, behavior, None, None, request_deserializer, response_serializer, None) def stream_stream_service_description( behavior, request_deserializer, response_serializer): """Creates an interfaces.RpcMethodServiceDescription for the given behavior. Args: behavior: A callable that implements a stream-stream RPC method that accepts an iterator of zero or more requests and an interfaces.RpcContext and returns an iterator of zero or more responses. request_deserializer: A callable that when called on a bytestring returns the request value corresponding to that bytestring. response_serializer: A callable that when called on a response value returns the bytestring corresponding to that value. Returns: An interfaces.RpcMethodServiceDescription constructed from the given arguments representing a streaming-request/streaming-response RPC method. """ return _RpcMethodDescription( interfaces.Cardinality.STREAM_STREAM, None, None, None, behavior, None, request_deserializer, response_serializer, None) grpc-0.11.1/src/python/grpcio/grpc/framework/alpha/interfaces.py0000644000175000017500000003214412600663151025030 0ustar apollockapollock# 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. """Interfaces of GRPC.""" import abc import enum # exceptions is referenced from specification in this module. from grpc.framework.alpha import exceptions # pylint: disable=unused-import from grpc.framework.foundation import activated from grpc.framework.foundation import future @enum.unique class Cardinality(enum.Enum): """Constants for the four cardinalities of RPC.""" UNARY_UNARY = 'request-unary/response-unary' UNARY_STREAM = 'request-unary/response-streaming' STREAM_UNARY = 'request-streaming/response-unary' STREAM_STREAM = 'request-streaming/response-streaming' @enum.unique class Abortion(enum.Enum): """Categories of RPC abortion.""" CANCELLED = 'cancelled' EXPIRED = 'expired' NETWORK_FAILURE = 'network failure' SERVICED_FAILURE = 'serviced failure' SERVICER_FAILURE = 'servicer failure' class CancellableIterator(object): """Implements the Iterator protocol and affords a cancel method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __iter__(self): """Returns the self object in accordance with the Iterator protocol.""" raise NotImplementedError() @abc.abstractmethod def next(self): """Returns a value or raises StopIteration per the Iterator protocol.""" raise NotImplementedError() @abc.abstractmethod def cancel(self): """Requests cancellation of whatever computation underlies this iterator.""" raise NotImplementedError() class RpcContext(object): """Provides RPC-related information and action.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): """Describes whether the RPC is active or has terminated.""" raise NotImplementedError() @abc.abstractmethod def time_remaining(self): """Describes the length of allowed time remaining for the RPC. Returns: A nonnegative float indicating the length of allowed time in seconds remaining for the RPC to complete before it is considered to have timed out. """ raise NotImplementedError() @abc.abstractmethod def add_abortion_callback(self, abortion_callback): """Registers a callback to be called if the RPC is aborted. Args: abortion_callback: A callable to be called and passed an Abortion value in the event of RPC abortion. """ raise NotImplementedError() class UnaryUnarySyncAsync(object): """Affords invoking a unary-unary RPC synchronously or asynchronously. Values implementing this interface are directly callable and present an "async" method. Both calls take a request value and a numeric timeout. Direct invocation of a value of this type invokes its associated RPC and blocks until the RPC's response is available. Calling the "async" method of a value of this type invokes its associated RPC and immediately returns a future.Future bound to the asynchronous execution of the RPC. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout): """Synchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: The response value for the RPC. Raises: exceptions.RpcError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def async(self, request, timeout): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A future.Future representing the RPC. In the event of RPC completion, the returned Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an exceptions.RpcError. """ raise NotImplementedError() class StreamUnarySyncAsync(object): """Affords invoking a stream-unary RPC synchronously or asynchronously. Values implementing this interface are directly callable and present an "async" method. Both calls take an iterator of request values and a numeric timeout. Direct invocation of a value of this type invokes its associated RPC and blocks until the RPC's response is available. Calling the "async" method of a value of this type invokes its associated RPC and immediately returns a future.Future bound to the asynchronous execution of the RPC. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request_iterator, timeout): """Synchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: The response value for the RPC. Raises: exceptions.RpcError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def async(self, request_iterator, timeout): """Asynchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A future.Future representing the RPC. In the event of RPC completion, the returned Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an exceptions.RpcError. """ raise NotImplementedError() class RpcMethodDescription(object): """A type for the common aspects of RPC method descriptions.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def cardinality(self): """Identifies the cardinality of this RpcMethodDescription. Returns: A Cardinality value identifying whether or not this RpcMethodDescription is request-unary or request-streaming and whether or not it is response-unary or response-streaming. """ raise NotImplementedError() class RpcMethodInvocationDescription(RpcMethodDescription): """Invocation-side description of an RPC method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def serialize_request(self, request): """Serializes a request value. Args: request: A request value appropriate for the RPC method described by this RpcMethodInvocationDescription. Returns: The serialization of the given request value as a bytestring. """ raise NotImplementedError() @abc.abstractmethod def deserialize_response(self, serialized_response): """Deserializes a response value. Args: serialized_response: A bytestring that is the serialization of a response value appropriate for the RPC method described by this RpcMethodInvocationDescription. Returns: A response value corresponding to the given bytestring. """ raise NotImplementedError() class RpcMethodServiceDescription(RpcMethodDescription): """Service-side description of an RPC method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def deserialize_request(self, serialized_request): """Deserializes a request value. Args: serialized_request: A bytestring that is the serialization of a request value appropriate for the RPC method described by this RpcMethodServiceDescription. Returns: A request value corresponding to the given bytestring. """ raise NotImplementedError() @abc.abstractmethod def serialize_response(self, response): """Serializes a response value. Args: response: A response value appropriate for the RPC method described by this RpcMethodServiceDescription. Returns: The serialization of the given response value as a bytestring. """ raise NotImplementedError() @abc.abstractmethod def service_unary_unary(self, request, context): """Carries out this RPC. This method may only be called if the cardinality of this RpcMethodServiceDescription is Cardinality.UNARY_UNARY. Args: request: A request value appropriate for the RPC method described by this RpcMethodServiceDescription. context: An RpcContext object for the RPC. Returns: A response value appropriate for the RPC method described by this RpcMethodServiceDescription. """ raise NotImplementedError() @abc.abstractmethod def service_unary_stream(self, request, context): """Carries out this RPC. This method may only be called if the cardinality of this RpcMethodServiceDescription is Cardinality.UNARY_STREAM. Args: request: A request value appropriate for the RPC method described by this RpcMethodServiceDescription. context: An RpcContext object for the RPC. Yields: Zero or more response values appropriate for the RPC method described by this RpcMethodServiceDescription. """ raise NotImplementedError() @abc.abstractmethod def service_stream_unary(self, request_iterator, context): """Carries out this RPC. This method may only be called if the cardinality of this RpcMethodServiceDescription is Cardinality.STREAM_UNARY. Args: request_iterator: An iterator of request values appropriate for the RPC method described by this RpcMethodServiceDescription. context: An RpcContext object for the RPC. Returns: A response value appropriate for the RPC method described by this RpcMethodServiceDescription. """ raise NotImplementedError() @abc.abstractmethod def service_stream_stream(self, request_iterator, context): """Carries out this RPC. This method may only be called if the cardinality of this RpcMethodServiceDescription is Cardinality.STREAM_STREAM. Args: request_iterator: An iterator of request values appropriate for the RPC method described by this RpcMethodServiceDescription. context: An RpcContext object for the RPC. Yields: Zero or more response values appropriate for the RPC method described by this RpcMethodServiceDescription. """ raise NotImplementedError() class Stub(object): """A stub with callable RPC method names for attributes. Instances of this type are context managers and only afford RPC invocation when used in context. Instances of this type, when used in context, respond to attribute access as follows: if the requested attribute is the name of a unary-unary RPC method, the value of the attribute will be a UnaryUnarySyncAsync with which to invoke the RPC method. If the requested attribute is the name of a unary-stream RPC method, the value of the attribute will be a callable taking a request object and a timeout parameter and returning a CancellableIterator that yields the response values of the RPC. If the requested attribute is the name of a stream-unary RPC method, the value of the attribute will be a StreamUnarySyncAsync with which to invoke the RPC method. If the requested attribute is the name of a stream-stream RPC method, the value of the attribute will be a callable taking an iterator of request objects and a timeout and returning a CancellableIterator that yields the response values of the RPC. In all cases indication of abortion is indicated by raising of exceptions.RpcError, exceptions.CancellationError, and exceptions.ExpirationError. """ __metaclass__ = abc.ABCMeta class Server(activated.Activated): """A GRPC Server.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def port(self): """Reports the port on which the server is serving. This method may only be called while the server is activated. Returns: The port on which the server is serving. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/alpha/_face_utilities.py0000644000175000017500000001720112600663151026032 0ustar apollockapollock# 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. import abc import collections # face_interfaces is referenced from specification in this module. from grpc.framework.common import cardinality from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import from grpc.framework.face import utilities as face_utilities from grpc.framework.alpha import _reexport from grpc.framework.alpha import interfaces def _qualified_name(service_name, method_name): return '/%s/%s' % (service_name, method_name) # TODO(nathaniel): This structure is getting bloated; it could be shrunk if # implementations._Stub used a generic rather than a dynamic underlying # face-layer stub. class InvocationBreakdown(object): """An intermediate representation of invocation-side views of RPC methods. Attributes: cardinalities: A dictionary from RPC method name to interfaces.Cardinality value. qualified_names: A dictionary from unqualified RPC method name to service-qualified RPC method name. face_cardinalities: A dictionary from service-qualified RPC method name to to cardinality.Cardinality value. request_serializers: A dictionary from service-qualified RPC method name to callable behavior to be used serializing request values for the RPC. response_deserializers: A dictionary from service-qualified RPC method name to callable behavior to be used deserializing response values for the RPC. """ __metaclass__ = abc.ABCMeta class _EasyInvocationBreakdown( InvocationBreakdown, collections.namedtuple( '_EasyInvocationBreakdown', ('cardinalities', 'qualified_names', 'face_cardinalities', 'request_serializers', 'response_deserializers'))): pass class ServiceBreakdown(object): """An intermediate representation of service-side views of RPC methods. Attributes: implementations: A dictionary from service-qualified RPC method name to face_interfaces.MethodImplementation implementing the RPC method. request_deserializers: A dictionary from service-qualified RPC method name to callable behavior to be used deserializing request values for the RPC. response_serializers: A dictionary from service-qualified RPC method name to callable behavior to be used serializing response values for the RPC. """ __metaclass__ = abc.ABCMeta class _EasyServiceBreakdown( ServiceBreakdown, collections.namedtuple( '_EasyServiceBreakdown', ('implementations', 'request_deserializers', 'response_serializers'))): pass def break_down_invocation(service_name, method_descriptions): """Derives an InvocationBreakdown from several RPC method descriptions. Args: service_name: The package-qualified full name of the service. method_descriptions: A dictionary from RPC method name to interfaces.RpcMethodInvocationDescription describing the RPCs. Returns: An InvocationBreakdown corresponding to the given method descriptions. """ cardinalities = {} qualified_names = {} face_cardinalities = {} request_serializers = {} response_deserializers = {} for name, method_description in method_descriptions.iteritems(): qualified_name = _qualified_name(service_name, name) method_cardinality = method_description.cardinality() cardinalities[name] = method_description.cardinality() qualified_names[name] = qualified_name face_cardinalities[qualified_name] = _reexport.common_cardinality( method_cardinality) request_serializers[qualified_name] = method_description.serialize_request response_deserializers[qualified_name] = ( method_description.deserialize_response) return _EasyInvocationBreakdown( cardinalities, qualified_names, face_cardinalities, request_serializers, response_deserializers) def break_down_service(service_name, method_descriptions): """Derives a ServiceBreakdown from several RPC method descriptions. Args: method_descriptions: A dictionary from RPC method name to interfaces.RpcMethodServiceDescription describing the RPCs. Returns: A ServiceBreakdown corresponding to the given method descriptions. """ implementations = {} request_deserializers = {} response_serializers = {} for name, method_description in method_descriptions.iteritems(): qualified_name = _qualified_name(service_name, name) method_cardinality = method_description.cardinality() if method_cardinality is interfaces.Cardinality.UNARY_UNARY: def service( request, face_rpc_context, service_behavior=method_description.service_unary_unary): return service_behavior( request, _reexport.rpc_context(face_rpc_context)) implementations[qualified_name] = face_utilities.unary_unary_inline( service) elif method_cardinality is interfaces.Cardinality.UNARY_STREAM: def service( request, face_rpc_context, service_behavior=method_description.service_unary_stream): return service_behavior( request, _reexport.rpc_context(face_rpc_context)) implementations[qualified_name] = face_utilities.unary_stream_inline( service) elif method_cardinality is interfaces.Cardinality.STREAM_UNARY: def service( request_iterator, face_rpc_context, service_behavior=method_description.service_stream_unary): return service_behavior( request_iterator, _reexport.rpc_context(face_rpc_context)) implementations[qualified_name] = face_utilities.stream_unary_inline( service) elif method_cardinality is interfaces.Cardinality.STREAM_STREAM: def service( request_iterator, face_rpc_context, service_behavior=method_description.service_stream_stream): return service_behavior( request_iterator, _reexport.rpc_context(face_rpc_context)) implementations[qualified_name] = face_utilities.stream_stream_inline( service) request_deserializers[qualified_name] = ( method_description.deserialize_request) response_serializers[qualified_name] = ( method_description.serialize_response) return _EasyServiceBreakdown( implementations, request_deserializers, response_serializers) grpc-0.11.1/src/python/grpcio/grpc/framework/alpha/_reexport.py0000644000175000017500000001535312600663151024717 0ustar apollockapollock# 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. from grpc.framework.common import cardinality from grpc.framework.face import exceptions as face_exceptions from grpc.framework.face import interfaces as face_interfaces from grpc.framework.foundation import future from grpc.framework.alpha import exceptions from grpc.framework.alpha import interfaces _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY = { interfaces.Cardinality.UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY, interfaces.Cardinality.UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM, interfaces.Cardinality.STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY, interfaces.Cardinality.STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM, } _ABORTION_REEXPORT = { face_interfaces.Abortion.CANCELLED: interfaces.Abortion.CANCELLED, face_interfaces.Abortion.EXPIRED: interfaces.Abortion.EXPIRED, face_interfaces.Abortion.NETWORK_FAILURE: interfaces.Abortion.NETWORK_FAILURE, face_interfaces.Abortion.SERVICED_FAILURE: interfaces.Abortion.SERVICED_FAILURE, face_interfaces.Abortion.SERVICER_FAILURE: interfaces.Abortion.SERVICER_FAILURE, } class _RpcError(exceptions.RpcError): pass def _reexport_error(face_rpc_error): if isinstance(face_rpc_error, face_exceptions.CancellationError): return exceptions.CancellationError() elif isinstance(face_rpc_error, face_exceptions.ExpirationError): return exceptions.ExpirationError() else: return _RpcError() def _as_face_abortion_callback(abortion_callback): def face_abortion_callback(face_abortion): abortion_callback(_ABORTION_REEXPORT[face_abortion]) return face_abortion_callback class _ReexportedFuture(future.Future): def __init__(self, face_future): self._face_future = face_future def cancel(self): return self._face_future.cancel() def cancelled(self): return self._face_future.cancelled() def running(self): return self._face_future.running() def done(self): return self._face_future.done() def result(self, timeout=None): try: return self._face_future.result(timeout=timeout) except face_exceptions.RpcError as e: raise _reexport_error(e) def exception(self, timeout=None): face_error = self._face_future.exception(timeout=timeout) return None if face_error is None else _reexport_error(face_error) def traceback(self, timeout=None): return self._face_future.traceback(timeout=timeout) def add_done_callback(self, fn): self._face_future.add_done_callback(lambda unused_face_future: fn(self)) def _call_reexporting_errors(behavior, *args, **kwargs): try: return behavior(*args, **kwargs) except face_exceptions.RpcError as e: raise _reexport_error(e) def _reexported_future(face_future): return _ReexportedFuture(face_future) class _CancellableIterator(interfaces.CancellableIterator): def __init__(self, face_cancellable_iterator): self._face_cancellable_iterator = face_cancellable_iterator def __iter__(self): return self def next(self): return _call_reexporting_errors(self._face_cancellable_iterator.next) def cancel(self): self._face_cancellable_iterator.cancel() class _RpcContext(interfaces.RpcContext): def __init__(self, face_rpc_context): self._face_rpc_context = face_rpc_context def is_active(self): return self._face_rpc_context.is_active() def time_remaining(self): return self._face_rpc_context.time_remaining() def add_abortion_callback(self, abortion_callback): self._face_rpc_context.add_abortion_callback( _as_face_abortion_callback(abortion_callback)) class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync): def __init__(self, face_unary_unary_multi_callable): self._underlying = face_unary_unary_multi_callable def __call__(self, request, timeout): return _call_reexporting_errors( self._underlying, request, timeout) def async(self, request, timeout): return _ReexportedFuture(self._underlying.future(request, timeout)) class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync): def __init__(self, face_stream_unary_multi_callable): self._underlying = face_stream_unary_multi_callable def __call__(self, request_iterator, timeout): return _call_reexporting_errors( self._underlying, request_iterator, timeout) def async(self, request_iterator, timeout): return _ReexportedFuture(self._underlying.future(request_iterator, timeout)) def common_cardinality(early_adopter_cardinality): return _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[ early_adopter_cardinality] def common_cardinalities(early_adopter_cardinalities): common_cardinalities = {} for name, early_adopter_cardinality in early_adopter_cardinalities.iteritems(): common_cardinalities[name] = _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[ early_adopter_cardinality] return common_cardinalities def rpc_context(face_rpc_context): return _RpcContext(face_rpc_context) def cancellable_iterator(face_cancellable_iterator): return _CancellableIterator(face_cancellable_iterator) def unary_unary_sync_async(face_unary_unary_multi_callable): return _UnaryUnarySyncAsync(face_unary_unary_multi_callable) def stream_unary_sync_async(face_stream_unary_multi_callable): return _StreamUnarySyncAsync(face_stream_unary_multi_callable) grpc-0.11.1/src/python/grpcio/grpc/framework/alpha/__init__.py0000644000175000017500000000277012600663151024446 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/core/0000755000175000017500000000000012600663151022172 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/core/_ingestion.py0000644000175000017500000004333312600663151024710 0ustar apollockapollock# 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. """State and behavior for ingestion during an operation.""" import abc import collections import enum from grpc.framework.core import _constants from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.foundation import abandonment from grpc.framework.foundation import callable_util from grpc.framework.interfaces.base import base _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!' _INGESTION_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!' class _SubscriptionCreation( collections.namedtuple( '_SubscriptionCreation', ('kind', 'subscription', 'code', 'details',))): """A sum type for the outcome of ingestion initialization. Attributes: kind: A Kind value coarsely indicating how subscription creation completed. subscription: The created subscription. Only present if kind is Kind.SUBSCRIPTION. code: A code value to be sent to the other side of the operation along with an indication that the operation is being aborted due to an error on the remote side of the operation. Only present if kind is Kind.REMOTE_ERROR. details: A details value to be sent to the other side of the operation along with an indication that the operation is being aborted due to an error on the remote side of the operation. Only present if kind is Kind.REMOTE_ERROR. """ @enum.unique class Kind(enum.Enum): SUBSCRIPTION = 'subscription' REMOTE_ERROR = 'remote error' ABANDONED = 'abandoned' class _SubscriptionCreator(object): """Common specification of subscription-creating behavior.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def create(self, group, method): """Creates the base.Subscription of the local customer. Any exceptions raised by this method should be attributed to and treated as defects in the customer code called by this method. Args: group: The group identifier of the operation. method: The method identifier of the operation. Returns: A _SubscriptionCreation describing the result of subscription creation. """ raise NotImplementedError() class _ServiceSubscriptionCreator(_SubscriptionCreator): """A _SubscriptionCreator appropriate for service-side use.""" def __init__(self, servicer, operation_context, output_operator): """Constructor. Args: servicer: The base.Servicer that will service the operation. operation_context: A base.OperationContext for the operation to be passed to the customer. output_operator: A base.Operator for the operation to be passed to the customer and to be called by the customer to accept operation data emitted by the customer. """ self._servicer = servicer self._operation_context = operation_context self._output_operator = output_operator def create(self, group, method): try: subscription = self._servicer.service( group, method, self._operation_context, self._output_operator) except base.NoSuchMethodError as e: return _SubscriptionCreation( _SubscriptionCreation.Kind.REMOTE_ERROR, None, e.code, e.details) except abandonment.Abandoned: return _SubscriptionCreation( _SubscriptionCreation.Kind.ABANDONED, None, None, None) else: return _SubscriptionCreation( _SubscriptionCreation.Kind.SUBSCRIPTION, subscription, None, None) def _wrap(behavior): def wrapped(*args, **kwargs): try: behavior(*args, **kwargs) except abandonment.Abandoned: return False else: return True return wrapped class _IngestionManager(_interfaces.IngestionManager): """An implementation of _interfaces.IngestionManager.""" def __init__( self, lock, pool, subscription, subscription_creator, termination_manager, transmission_manager, expiration_manager, protocol_manager): """Constructor. Args: lock: The operation-wide lock. pool: A thread pool in which to execute customer code. subscription: A base.Subscription describing the customer's interest in operation values from the other side. May be None if subscription_creator is not None. subscription_creator: A _SubscriptionCreator wrapping the portion of customer code that when called returns the base.Subscription describing the customer's interest in operation values from the other side. May be None if subscription is not None. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. protocol_manager: The _interfaces.ProtocolManager for the operation. """ self._lock = lock self._pool = pool self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = expiration_manager self._protocol_manager = protocol_manager if subscription is None: self._subscription_creator = subscription_creator self._wrapped_operator = None elif subscription.kind is base.Subscription.Kind.FULL: self._subscription_creator = None self._wrapped_operator = _wrap(subscription.operator.advance) else: # TODO(nathaniel): Support other subscriptions. raise ValueError('Unsupported subscription "%s"!' % subscription.kind) self._pending_initial_metadata = None self._pending_payloads = [] self._pending_completion = None self._local_allowance = 1 # A nonnegative integer or None, with None indicating that the local # customer is done emitting anyway so there's no need to bother it by # informing it that the remote customer has granted it further permission to # emit. self._remote_allowance = 0 self._processing = False def _abort_internal_only(self): self._subscription_creator = None self._wrapped_operator = None self._pending_initial_metadata = None self._pending_payloads = None self._pending_completion = None def _abort_and_notify(self, outcome_kind, code, details): self._abort_internal_only() if self._termination_manager.outcome is None: outcome = _utilities.Outcome(outcome_kind, code, details) self._termination_manager.abort(outcome) self._transmission_manager.abort(outcome) self._expiration_manager.terminate() def _operator_next(self): """Computes the next step for full-subscription ingestion. Returns: An initial_metadata, payload, completion, allowance, continue quintet indicating what operation values (if any) are available to pass into customer code and whether or not there is anything immediately actionable to call customer code to do. """ if self._wrapped_operator is None: return None, None, None, None, False else: initial_metadata, payload, completion, allowance, action = [None] * 5 if self._pending_initial_metadata is not None: initial_metadata = self._pending_initial_metadata self._pending_initial_metadata = None action = True if self._pending_payloads and 0 < self._local_allowance: payload = self._pending_payloads.pop(0) self._local_allowance -= 1 action = True if not self._pending_payloads and self._pending_completion is not None: completion = self._pending_completion self._pending_completion = None action = True if self._remote_allowance is not None and 0 < self._remote_allowance: allowance = self._remote_allowance self._remote_allowance = 0 action = True return initial_metadata, payload, completion, allowance, bool(action) def _operator_process( self, wrapped_operator, initial_metadata, payload, completion, allowance): while True: advance_outcome = callable_util.call_logging_exceptions( wrapped_operator, _INGESTION_EXCEPTION_LOG_MESSAGE, initial_metadata=initial_metadata, payload=payload, completion=completion, allowance=allowance) if advance_outcome.exception is None: if advance_outcome.return_value: with self._lock: if self._termination_manager.outcome is not None: return if completion is not None: self._termination_manager.ingestion_complete() initial_metadata, payload, completion, allowance, moar = ( self._operator_next()) if not moar: self._processing = False return else: with self._lock: if self._termination_manager.outcome is None: self._abort_and_notify( base.Outcome.Kind.LOCAL_FAILURE, None, None) return else: with self._lock: if self._termination_manager.outcome is None: self._abort_and_notify(base.Outcome.Kind.LOCAL_FAILURE, None, None) return def _operator_post_create(self, subscription): wrapped_operator = _wrap(subscription.operator.advance) with self._lock: if self._termination_manager.outcome is not None: return self._wrapped_operator = wrapped_operator self._subscription_creator = None metadata, payload, completion, allowance, moar = self._operator_next() if not moar: self._processing = False return self._operator_process( wrapped_operator, metadata, payload, completion, allowance) def _create(self, subscription_creator, group, name): outcome = callable_util.call_logging_exceptions( subscription_creator.create, _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE, group, name) if outcome.return_value is None: with self._lock: if self._termination_manager.outcome is None: self._abort_and_notify(base.Outcome.Kind.LOCAL_FAILURE, None, None) elif outcome.return_value.kind is _SubscriptionCreation.Kind.ABANDONED: with self._lock: if self._termination_manager.outcome is None: self._abort_and_notify(base.Outcome.Kind.LOCAL_FAILURE, None, None) elif outcome.return_value.kind is _SubscriptionCreation.Kind.REMOTE_ERROR: code = outcome.return_value.code details = outcome.return_value.details with self._lock: if self._termination_manager.outcome is None: self._abort_and_notify( base.Outcome.Kind.REMOTE_FAILURE, code, details) elif outcome.return_value.subscription.kind is base.Subscription.Kind.FULL: self._protocol_manager.set_protocol_receiver( outcome.return_value.subscription.protocol_receiver) self._operator_post_create(outcome.return_value.subscription) else: # TODO(nathaniel): Support other subscriptions. raise ValueError( 'Unsupported "%s"!' % outcome.return_value.subscription.kind) def _store_advance(self, initial_metadata, payload, completion, allowance): if initial_metadata is not None: self._pending_initial_metadata = initial_metadata if payload is not None: self._pending_payloads.append(payload) if completion is not None: self._pending_completion = completion if allowance is not None and self._remote_allowance is not None: self._remote_allowance += allowance def _operator_advance(self, initial_metadata, payload, completion, allowance): if self._processing: self._store_advance(initial_metadata, payload, completion, allowance) else: action = False if initial_metadata is not None: action = True if payload is not None: if 0 < self._local_allowance: self._local_allowance -= 1 action = True else: self._pending_payloads.append(payload) payload = False if completion is not None: if self._pending_payloads: self._pending_completion = completion else: action = True if allowance is not None and self._remote_allowance is not None: allowance += self._remote_allowance self._remote_allowance = 0 action = True if action: self._pool.submit( callable_util.with_exceptions_logged( self._operator_process, _constants.INTERNAL_ERROR_LOG_MESSAGE), self._wrapped_operator, initial_metadata, payload, completion, allowance) def set_group_and_method(self, group, method): """See _interfaces.IngestionManager.set_group_and_method for spec.""" if self._subscription_creator is not None and not self._processing: self._pool.submit( callable_util.with_exceptions_logged( self._create, _constants.INTERNAL_ERROR_LOG_MESSAGE), self._subscription_creator, group, method) self._processing = True def add_local_allowance(self, allowance): """See _interfaces.IngestionManager.add_local_allowance for spec.""" if any((self._subscription_creator, self._wrapped_operator,)): self._local_allowance += allowance if not self._processing: initial_metadata, payload, completion, allowance, moar = ( self._operator_next()) if moar: self._pool.submit( callable_util.with_exceptions_logged( self._operator_process, _constants.INTERNAL_ERROR_LOG_MESSAGE), initial_metadata, payload, completion, allowance) def local_emissions_done(self): self._remote_allowance = None def advance(self, initial_metadata, payload, completion, allowance): """See _interfaces.IngestionManager.advance for specification.""" if self._subscription_creator is not None: self._store_advance(initial_metadata, payload, completion, allowance) elif self._wrapped_operator is not None: self._operator_advance(initial_metadata, payload, completion, allowance) def invocation_ingestion_manager( subscription, lock, pool, termination_manager, transmission_manager, expiration_manager, protocol_manager): """Creates an IngestionManager appropriate for invocation-side use. Args: subscription: A base.Subscription indicating the customer's interest in the data and results from the service-side of the operation. lock: The operation-wide lock. pool: A thread pool in which to execute customer code. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. protocol_manager: The _interfaces.ProtocolManager for the operation. Returns: An IngestionManager appropriate for invocation-side use. """ return _IngestionManager( lock, pool, subscription, None, termination_manager, transmission_manager, expiration_manager, protocol_manager) def service_ingestion_manager( servicer, operation_context, output_operator, lock, pool, termination_manager, transmission_manager, expiration_manager, protocol_manager): """Creates an IngestionManager appropriate for service-side use. The returned IngestionManager will require its set_group_and_name method to be called before its advance method may be called. Args: servicer: A base.Servicer for servicing the operation. operation_context: A base.OperationContext for the operation to be passed to the customer. output_operator: A base.Operator for the operation to be passed to the customer and to be called by the customer to accept operation data output by the customer. lock: The operation-wide lock. pool: A thread pool in which to execute customer code. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. protocol_manager: The _interfaces.ProtocolManager for the operation. Returns: An IngestionManager appropriate for service-side use. """ subscription_creator = _ServiceSubscriptionCreator( servicer, operation_context, output_operator) return _IngestionManager( lock, pool, None, subscription_creator, termination_manager, transmission_manager, expiration_manager, protocol_manager) grpc-0.11.1/src/python/grpcio/grpc/framework/core/_expiration.py0000644000175000017500000001364712600663151025100 0ustar apollockapollock# 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. """State and behavior for operation expiration.""" import time from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.foundation import later from grpc.framework.interfaces.base import base class _ExpirationManager(_interfaces.ExpirationManager): """An implementation of _interfaces.ExpirationManager.""" def __init__( self, commencement, timeout, maximum_timeout, lock, termination_manager, transmission_manager): """Constructor. Args: commencement: The time in seconds since the epoch at which the operation began. timeout: A length of time in seconds to allow for the operation to run. maximum_timeout: The maximum length of time in seconds to allow for the operation to run despite what is requested via this object's change_timout method. lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. """ self._lock = lock self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._commencement = commencement self._maximum_timeout = maximum_timeout self._timeout = timeout self._deadline = commencement + timeout self._index = None self._future = None def _expire(self, index): def expire(): with self._lock: if self._future is not None and index == self._index: self._future = None self._termination_manager.expire() self._transmission_manager.abort( _utilities.Outcome(base.Outcome.Kind.EXPIRED, None, None)) return expire def start(self): self._index = 0 self._future = later.later(self._timeout, self._expire(0)) def change_timeout(self, timeout): if self._future is not None and timeout != self._timeout: self._future.cancel() new_timeout = min(timeout, self._maximum_timeout) new_index = self._index + 1 self._timeout = new_timeout self._deadline = self._commencement + new_timeout self._index = new_index delay = self._deadline - time.time() self._future = later.later(delay, self._expire(new_index)) if new_timeout != timeout: self._transmission_manager.timeout(new_timeout) def deadline(self): return self._deadline def terminate(self): if self._future: self._future.cancel() self._future = None self._deadline_index = None def invocation_expiration_manager( timeout, lock, termination_manager, transmission_manager): """Creates an _interfaces.ExpirationManager appropriate for front-side use. Args: timeout: A length of time in seconds to allow for the operation to run. lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. Returns: An _interfaces.ExpirationManager appropriate for invocation-side use. """ expiration_manager = _ExpirationManager( time.time(), timeout, timeout, lock, termination_manager, transmission_manager) expiration_manager.start() return expiration_manager def service_expiration_manager( timeout, default_timeout, maximum_timeout, lock, termination_manager, transmission_manager): """Creates an _interfaces.ExpirationManager appropriate for back-side use. Args: timeout: A length of time in seconds to allow for the operation to run. May be None in which case default_timeout will be used. default_timeout: The default length of time in seconds to allow for the operation to run if the front-side customer has not specified such a value (or if the value they specified is not yet known). maximum_timeout: The maximum length of time in seconds to allow for the operation to run. lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. Returns: An _interfaces.ExpirationManager appropriate for service-side use. """ expiration_manager = _ExpirationManager( time.time(), default_timeout if timeout is None else timeout, maximum_timeout, lock, termination_manager, transmission_manager) expiration_manager.start() return expiration_manager grpc-0.11.1/src/python/grpcio/grpc/framework/core/_constants.py0000644000175000017500000000557512600663151024733 0ustar apollockapollock# 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. """Private constants for the package.""" from grpc.framework.interfaces.base import base from grpc.framework.interfaces.links import links TICKET_SUBSCRIPTION_FOR_BASE_SUBSCRIPTION_KIND = { base.Subscription.Kind.NONE: links.Ticket.Subscription.NONE, base.Subscription.Kind.TERMINATION_ONLY: links.Ticket.Subscription.TERMINATION, base.Subscription.Kind.FULL: links.Ticket.Subscription.FULL, } # Mapping from abortive operation outcome to ticket termination to be # sent to the other side of the operation, or None to indicate that no # ticket should be sent to the other side in the event of such an # outcome. ABORTION_OUTCOME_TO_TICKET_TERMINATION = { base.Outcome.Kind.CANCELLED: links.Ticket.Termination.CANCELLATION, base.Outcome.Kind.EXPIRED: links.Ticket.Termination.EXPIRATION, base.Outcome.Kind.LOCAL_SHUTDOWN: links.Ticket.Termination.SHUTDOWN, base.Outcome.Kind.REMOTE_SHUTDOWN: None, base.Outcome.Kind.RECEPTION_FAILURE: links.Ticket.Termination.RECEPTION_FAILURE, base.Outcome.Kind.TRANSMISSION_FAILURE: None, base.Outcome.Kind.LOCAL_FAILURE: links.Ticket.Termination.LOCAL_FAILURE, base.Outcome.Kind.REMOTE_FAILURE: links.Ticket.Termination.REMOTE_FAILURE, } INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Core) internal error! )-:' TERMINATION_CALLBACK_EXCEPTION_LOG_MESSAGE = ( 'Exception calling termination callback!') grpc-0.11.1/src/python/grpcio/grpc/framework/core/_end.py0000644000175000017500000002126612600663151023460 0ustar apollockapollock# 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. """Implementation of base.End.""" import abc import threading import uuid from grpc.framework.core import _operation from grpc.framework.core import _utilities from grpc.framework.foundation import callable_util from grpc.framework.foundation import later from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.base import base from grpc.framework.interfaces.links import links from grpc.framework.interfaces.links import utilities _IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!' class End(base.End, links.Link): """A bridge between base.End and links.Link. Implementations of this interface translate arriving tickets into calls on application objects implementing base interfaces and translate calls from application objects implementing base interfaces into tickets sent to a joined link. """ __metaclass__ = abc.ABCMeta class _Cycle(object): """State for a single start-stop End lifecycle.""" def __init__(self, pool): self.pool = pool self.grace = False self.futures = [] self.operations = {} self.idle_actions = [] def _abort(operations): for operation in operations: operation.abort(base.Outcome.Kind.LOCAL_SHUTDOWN) def _cancel_futures(futures): for future in futures: future.cancel() def _future_shutdown(lock, cycle, event): def in_future(): with lock: _abort(cycle.operations.values()) _cancel_futures(cycle.futures) return in_future def _termination_action(lock, stats, operation_id, cycle): """Constructs the termination action for a single operation. Args: lock: A lock to hold during the termination action. stats: A mapping from base.Outcome.Kind values to integers to increment with the outcome kind given to the termination action. operation_id: The operation ID for the termination action. cycle: A _Cycle value to be updated during the termination action. Returns: A callable that takes an operation outcome kind as its sole parameter and that should be used as the termination action for the operation associated with the given operation ID. """ def termination_action(outcome_kind): with lock: stats[outcome_kind] += 1 cycle.operations.pop(operation_id, None) if not cycle.operations: for action in cycle.idle_actions: cycle.pool.submit(action) cycle.idle_actions = [] if cycle.grace: _cancel_futures(cycle.futures) cycle.pool.shutdown(wait=False) return termination_action class _End(End): """An End implementation.""" def __init__(self, servicer_package): """Constructor. Args: servicer_package: A _ServicerPackage for servicing operations or None if this end will not be used to service operations. """ self._lock = threading.Condition() self._servicer_package = servicer_package self._stats = {outcome_kind: 0 for outcome_kind in base.Outcome.Kind} self._mate = None self._cycle = None def start(self): """See base.End.start for specification.""" with self._lock: if self._cycle is not None: raise ValueError('Tried to start a not-stopped End!') else: self._cycle = _Cycle(logging_pool.pool(1)) def stop(self, grace): """See base.End.stop for specification.""" with self._lock: if self._cycle is None: event = threading.Event() event.set() return event elif not self._cycle.operations: event = threading.Event() self._cycle.pool.submit(event.set) self._cycle.pool.shutdown(wait=False) self._cycle = None return event else: self._cycle.grace = True event = threading.Event() self._cycle.idle_actions.append(event.set) if 0 < grace: future = later.later( grace, _future_shutdown(self._lock, self._cycle, event)) self._cycle.futures.append(future) else: _abort(self._cycle.operations.values()) return event def operate( self, group, method, subscription, timeout, initial_metadata=None, payload=None, completion=None, protocol_options=None): """See base.End.operate for specification.""" operation_id = uuid.uuid4() with self._lock: if self._cycle is None or self._cycle.grace: raise ValueError('Can\'t operate on stopped or stopping End!') termination_action = _termination_action( self._lock, self._stats, operation_id, self._cycle) operation = _operation.invocation_operate( operation_id, group, method, subscription, timeout, protocol_options, initial_metadata, payload, completion, self._mate.accept_ticket, termination_action, self._cycle.pool) self._cycle.operations[operation_id] = operation return operation.context, operation.operator def operation_stats(self): """See base.End.operation_stats for specification.""" with self._lock: return dict(self._stats) def add_idle_action(self, action): """See base.End.add_idle_action for specification.""" with self._lock: if self._cycle is None: raise ValueError('Can\'t add idle action to stopped End!') action_with_exceptions_logged = callable_util.with_exceptions_logged( action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE) if self._cycle.operations: self._cycle.idle_actions.append(action_with_exceptions_logged) else: self._cycle.pool.submit(action_with_exceptions_logged) def accept_ticket(self, ticket): """See links.Link.accept_ticket for specification.""" with self._lock: if self._cycle is not None: operation = self._cycle.operations.get(ticket.operation_id) if operation is not None: operation.handle_ticket(ticket) elif self._servicer_package is not None and not self._cycle.grace: termination_action = _termination_action( self._lock, self._stats, ticket.operation_id, self._cycle) operation = _operation.service_operate( self._servicer_package, ticket, self._mate.accept_ticket, termination_action, self._cycle.pool) if operation is not None: self._cycle.operations[ticket.operation_id] = operation def join_link(self, link): """See links.Link.join_link for specification.""" with self._lock: self._mate = utilities.NULL_LINK if link is None else link def serviceless_end_link(): """Constructs an End usable only for invoking operations. Returns: An End usable for translating operations into ticket exchange. """ return _End(None) def serviceful_end_link(servicer, default_timeout, maximum_timeout): """Constructs an End capable of servicing operations. Args: servicer: An interfaces.Servicer for servicing operations. default_timeout: A length of time in seconds to be used as the default time alloted for a single operation. maximum_timeout: A length of time in seconds to be used as the maximum time alloted for a single operation. Returns: An End capable of servicing the operations requested of it through ticket exchange. """ return _End( _utilities.ServicerPackage(servicer, default_timeout, maximum_timeout)) grpc-0.11.1/src/python/grpcio/grpc/framework/core/implementations.py0000644000175000017500000000544712600663151025766 0ustar apollockapollock# 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. """Entry points into the ticket-exchange-based base layer implementation.""" # base and links are referenced from specification in this module. from grpc.framework.core import _end from grpc.framework.interfaces.base import base # pylint: disable=unused-import from grpc.framework.interfaces.links import links # pylint: disable=unused-import def invocation_end_link(): """Creates a base.End-links.Link suitable for operation invocation. Returns: An object that is both a base.End and a links.Link, that supports operation invocation, and that translates operation invocation into ticket exchange. """ return _end.serviceless_end_link() def service_end_link(servicer, default_timeout, maximum_timeout): """Creates a base.End-links.Link suitable for operation service. Args: servicer: A base.Servicer for servicing operations. default_timeout: A length of time in seconds to be used as the default time alloted for a single operation. maximum_timeout: A length of time in seconds to be used as the maximum time alloted for a single operation. Returns: An object that is both a base.End and a links.Link and that services operations that arrive at it through ticket exchange. """ return _end.serviceful_end_link(servicer, default_timeout, maximum_timeout) grpc-0.11.1/src/python/grpcio/grpc/framework/core/_emission.py0000644000175000017500000001034612600663151024535 0ustar apollockapollock# 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. """State and behavior for handling emitted values.""" from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.interfaces.base import base class EmissionManager(_interfaces.EmissionManager): """An EmissionManager implementation.""" def __init__( self, lock, termination_manager, transmission_manager, expiration_manager): """Constructor. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ self._lock = lock self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = expiration_manager self._ingestion_manager = None self._initial_metadata_seen = False self._payload_seen = False self._completion_seen = False def set_ingestion_manager(self, ingestion_manager): """Sets the ingestion manager with which this manager will cooperate. Args: ingestion_manager: The _interfaces.IngestionManager for the operation. """ self._ingestion_manager = ingestion_manager def advance( self, initial_metadata=None, payload=None, completion=None, allowance=None): initial_metadata_present = initial_metadata is not None payload_present = payload is not None completion_present = completion is not None allowance_present = allowance is not None with self._lock: if self._termination_manager.outcome is None: if (initial_metadata_present and ( self._initial_metadata_seen or self._payload_seen or self._completion_seen) or payload_present and self._completion_seen or completion_present and self._completion_seen or allowance_present and allowance <= 0): outcome = _utilities.Outcome( base.Outcome.Kind.LOCAL_FAILURE, None, None) self._termination_manager.abort(outcome) self._transmission_manager.abort(outcome) self._expiration_manager.terminate() else: self._initial_metadata_seen |= initial_metadata_present self._payload_seen |= payload_present self._completion_seen |= completion_present if completion_present: self._termination_manager.emission_complete() self._ingestion_manager.local_emissions_done() self._transmission_manager.advance( initial_metadata, payload, completion, allowance) if allowance_present: self._ingestion_manager.add_local_allowance(allowance) grpc-0.11.1/src/python/grpcio/grpc/framework/core/_termination.py0000644000175000017500000001750412600663151025243 0ustar apollockapollock# 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. """State and behavior for operation termination.""" import abc from grpc.framework.core import _constants from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.foundation import callable_util from grpc.framework.interfaces.base import base def _invocation_completion_predicate( unused_emission_complete, unused_transmission_complete, unused_reception_complete, ingestion_complete): return ingestion_complete def _service_completion_predicate( unused_emission_complete, transmission_complete, unused_reception_complete, unused_ingestion_complete): return transmission_complete class TerminationManager(_interfaces.TerminationManager): """A _interfaces.TransmissionManager on which another manager may be set.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_expiration_manager(self, expiration_manager): """Sets the expiration manager with which this manager will interact. Args: expiration_manager: The _interfaces.ExpirationManager associated with the current operation. """ raise NotImplementedError() class _TerminationManager(TerminationManager): """An implementation of TerminationManager.""" def __init__(self, predicate, action, pool): """Constructor. Args: predicate: One of _invocation_completion_predicate or _service_completion_predicate to be used to determine when the operation has completed. action: A behavior to pass the operation outcome's kind on operation termination. pool: A thread pool. """ self._predicate = predicate self._action = action self._pool = pool self._expiration_manager = None self._callbacks = [] self._code = None self._details = None self._emission_complete = False self._transmission_complete = False self._reception_complete = False self._ingestion_complete = False # The None-ness of outcome is the operation-wide record of whether and how # the operation has terminated. self.outcome = None def set_expiration_manager(self, expiration_manager): self._expiration_manager = expiration_manager def _terminate_internal_only(self, outcome): """Terminates the operation. Args: outcome: A base.Outcome describing the outcome of the operation. """ self.outcome = outcome callbacks = list(self._callbacks) self._callbacks = None act = callable_util.with_exceptions_logged( self._action, _constants.INTERNAL_ERROR_LOG_MESSAGE) # TODO(issue 3202): Don't call the local application's callbacks if it has # previously shown a programming defect. if False and outcome.kind is base.Outcome.Kind.LOCAL_FAILURE: self._pool.submit(act, base.Outcome.Kind.LOCAL_FAILURE) else: def call_callbacks_and_act(callbacks, outcome): for callback in callbacks: callback_outcome = callable_util.call_logging_exceptions( callback, _constants.TERMINATION_CALLBACK_EXCEPTION_LOG_MESSAGE, outcome) if callback_outcome.exception is not None: act_outcome_kind = base.Outcome.Kind.LOCAL_FAILURE break else: act_outcome_kind = outcome.kind act(act_outcome_kind) self._pool.submit( callable_util.with_exceptions_logged( call_callbacks_and_act, _constants.INTERNAL_ERROR_LOG_MESSAGE), callbacks, outcome) def _terminate_and_notify(self, outcome): self._terminate_internal_only(outcome) self._expiration_manager.terminate() def _perhaps_complete(self): if self._predicate( self._emission_complete, self._transmission_complete, self._reception_complete, self._ingestion_complete): self._terminate_and_notify( _utilities.Outcome( base.Outcome.Kind.COMPLETED, self._code, self._details)) return True else: return False def is_active(self): """See _interfaces.TerminationManager.is_active for specification.""" return self.outcome is None def add_callback(self, callback): """See _interfaces.TerminationManager.add_callback for specification.""" if self.outcome is None: self._callbacks.append(callback) return None else: return self.outcome def emission_complete(self): """See superclass method for specification.""" if self.outcome is None: self._emission_complete = True self._perhaps_complete() def transmission_complete(self): """See superclass method for specification.""" if self.outcome is None: self._transmission_complete = True return self._perhaps_complete() else: return False def reception_complete(self, code, details): """See superclass method for specification.""" if self.outcome is None: self._reception_complete = True self._code = code self._details = details self._perhaps_complete() def ingestion_complete(self): """See superclass method for specification.""" if self.outcome is None: self._ingestion_complete = True self._perhaps_complete() def expire(self): """See _interfaces.TerminationManager.expire for specification.""" self._terminate_internal_only( _utilities.Outcome(base.Outcome.Kind.EXPIRED, None, None)) def abort(self, outcome): """See _interfaces.TerminationManager.abort for specification.""" self._terminate_and_notify(outcome) def invocation_termination_manager(action, pool): """Creates a TerminationManager appropriate for invocation-side use. Args: action: An action to call on operation termination. pool: A thread pool in which to execute the passed action and any termination callbacks that are registered during the operation. Returns: A TerminationManager appropriate for invocation-side use. """ return _TerminationManager(_invocation_completion_predicate, action, pool) def service_termination_manager(action, pool): """Creates a TerminationManager appropriate for service-side use. Args: action: An action to call on operation termination. pool: A thread pool in which to execute the passed action and any termination callbacks that are registered during the operation. Returns: A TerminationManager appropriate for service-side use. """ return _TerminationManager(_service_completion_predicate, action, pool) grpc-0.11.1/src/python/grpcio/grpc/framework/core/__init__.py0000644000175000017500000000277212600663151024313 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/core/_reception.py0000644000175000017500000001470412600663151024701 0ustar apollockapollock# 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. """State and behavior for ticket reception.""" from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.interfaces.base import base from grpc.framework.interfaces.base import utilities from grpc.framework.interfaces.links import links _REMOTE_TICKET_TERMINATION_TO_LOCAL_OUTCOME_KIND = { links.Ticket.Termination.CANCELLATION: base.Outcome.Kind.CANCELLED, links.Ticket.Termination.EXPIRATION: base.Outcome.Kind.EXPIRED, links.Ticket.Termination.SHUTDOWN: base.Outcome.Kind.REMOTE_SHUTDOWN, links.Ticket.Termination.RECEPTION_FAILURE: base.Outcome.Kind.RECEPTION_FAILURE, links.Ticket.Termination.TRANSMISSION_FAILURE: base.Outcome.Kind.TRANSMISSION_FAILURE, links.Ticket.Termination.LOCAL_FAILURE: base.Outcome.Kind.REMOTE_FAILURE, links.Ticket.Termination.REMOTE_FAILURE: base.Outcome.Kind.LOCAL_FAILURE, } _RECEPTION_FAILURE_OUTCOME = _utilities.Outcome( base.Outcome.Kind.RECEPTION_FAILURE, None, None) def _carrying_protocol_context(ticket): return ticket.protocol is not None and ticket.protocol.kind in ( links.Protocol.Kind.INVOCATION_CONTEXT, links.Protocol.Kind.SERVICER_CONTEXT,) class ReceptionManager(_interfaces.ReceptionManager): """A ReceptionManager based around a _Receiver passed to it.""" def __init__( self, termination_manager, transmission_manager, expiration_manager, protocol_manager, ingestion_manager): """Constructor. Args: termination_manager: The operation's _interfaces.TerminationManager. transmission_manager: The operation's _interfaces.TransmissionManager. expiration_manager: The operation's _interfaces.ExpirationManager. protocol_manager: The operation's _interfaces.ProtocolManager. ingestion_manager: The operation's _interfaces.IngestionManager. """ self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = expiration_manager self._protocol_manager = protocol_manager self._ingestion_manager = ingestion_manager self._lowest_unseen_sequence_number = 0 self._out_of_sequence_tickets = {} self._aborted = False def _abort(self, outcome): self._aborted = True if self._termination_manager.outcome is None: self._termination_manager.abort(outcome) self._transmission_manager.abort(None) self._expiration_manager.terminate() def _sequence_failure(self, ticket): """Determines a just-arrived ticket's sequential legitimacy. Args: ticket: A just-arrived ticket. Returns: True if the ticket is sequentially legitimate; False otherwise. """ if ticket.sequence_number < self._lowest_unseen_sequence_number: return True elif ticket.sequence_number in self._out_of_sequence_tickets: return True else: return False def _process_one(self, ticket): if ticket.sequence_number == 0: self._ingestion_manager.set_group_and_method(ticket.group, ticket.method) if _carrying_protocol_context(ticket): self._protocol_manager.accept_protocol_context(ticket.protocol.value) else: self._protocol_manager.accept_protocol_context(None) if ticket.timeout is not None: self._expiration_manager.change_timeout(ticket.timeout) if ticket.termination is None: completion = None else: completion = utilities.completion( ticket.terminal_metadata, ticket.code, ticket.message) self._termination_manager.reception_complete(ticket.code, ticket.message) self._ingestion_manager.advance( ticket.initial_metadata, ticket.payload, completion, ticket.allowance) if ticket.allowance is not None: self._transmission_manager.allowance(ticket.allowance) def _process(self, ticket): """Process those tickets ready to be processed. Args: ticket: A just-arrived ticket the sequence number of which matches this _ReceptionManager's _lowest_unseen_sequence_number field. """ while True: self._process_one(ticket) next_ticket = self._out_of_sequence_tickets.pop( ticket.sequence_number + 1, None) if next_ticket is None: self._lowest_unseen_sequence_number = ticket.sequence_number + 1 return else: ticket = next_ticket def receive_ticket(self, ticket): """See _interfaces.ReceptionManager.receive_ticket for specification.""" if self._aborted: return elif self._sequence_failure(ticket): self._abort(_RECEPTION_FAILURE_OUTCOME) elif ticket.termination not in (None, links.Ticket.Termination.COMPLETION): outcome_kind = _REMOTE_TICKET_TERMINATION_TO_LOCAL_OUTCOME_KIND[ ticket.termination] self._abort( _utilities.Outcome(outcome_kind, ticket.code, ticket.message)) elif ticket.sequence_number == self._lowest_unseen_sequence_number: self._process(ticket) else: self._out_of_sequence_tickets[ticket.sequence_number] = ticket grpc-0.11.1/src/python/grpcio/grpc/framework/core/_utilities.py0000644000175000017500000000430212600663151024715 0ustar apollockapollock# 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. """Package-internal utilities.""" import collections from grpc.framework.interfaces.base import base class ServicerPackage( collections.namedtuple( 'ServicerPackage', ('servicer', 'default_timeout', 'maximum_timeout'))): """A trivial bundle class. Attributes: servicer: A base.Servicer. default_timeout: A float indicating the length of time in seconds to allow for an operation invoked without a timeout. maximum_timeout: A float indicating the maximum length of time in seconds to allow for an operation. """ class Outcome( base.Outcome, collections.namedtuple('Outcome', ('kind', 'code', 'details',))): """A trivial implementation of base.Outcome.""" grpc-0.11.1/src/python/grpcio/grpc/framework/core/_context.py0000644000175000017500000000734512600663151024400 0ustar apollockapollock# 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. """State and behavior for operation context.""" import time # _interfaces is referenced from specification in this module. from grpc.framework.core import _interfaces # pylint: disable=unused-import from grpc.framework.core import _utilities from grpc.framework.interfaces.base import base class OperationContext(base.OperationContext): """An implementation of interfaces.OperationContext.""" def __init__( self, lock, termination_manager, transmission_manager, expiration_manager): """Constructor. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ self._lock = lock self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = expiration_manager def _abort(self, outcome_kind): with self._lock: if self._termination_manager.outcome is None: outcome = _utilities.Outcome(outcome_kind, None, None) self._termination_manager.abort(outcome) self._transmission_manager.abort(outcome) self._expiration_manager.terminate() def outcome(self): """See base.OperationContext.outcome for specification.""" with self._lock: return self._termination_manager.outcome def add_termination_callback(self, callback): """See base.OperationContext.add_termination_callback.""" with self._lock: if self._termination_manager.outcome is None: self._termination_manager.add_callback(callback) return None else: return self._termination_manager.outcome def time_remaining(self): """See base.OperationContext.time_remaining for specification.""" with self._lock: deadline = self._expiration_manager.deadline() return max(0.0, deadline - time.time()) def cancel(self): """See base.OperationContext.cancel for specification.""" self._abort(base.Outcome.Kind.CANCELLED) def fail(self, exception): """See base.OperationContext.fail for specification.""" self._abort(base.Outcome.Kind.LOCAL_FAILURE) grpc-0.11.1/src/python/grpcio/grpc/framework/core/_interfaces.py0000644000175000017500000002576112600663151025041 0ustar apollockapollock# 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. """Package-internal interfaces.""" import abc from grpc.framework.interfaces.base import base class TerminationManager(object): """An object responsible for handling the termination of an operation. Attributes: outcome: None if the operation is active or a base.Outcome value if it has terminated. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def add_callback(self, callback): """Registers a callback to be called on operation termination. If the operation has already terminated the callback will not be called. Args: callback: A callable that will be passed a base.Outcome value. Returns: None if the operation has not yet terminated and the passed callback will be called when it does, or a base.Outcome value describing the operation termination if the operation has terminated and the callback will not be called as a result of this method call. """ raise NotImplementedError() @abc.abstractmethod def emission_complete(self): """Indicates that emissions from customer code have completed.""" raise NotImplementedError() @abc.abstractmethod def transmission_complete(self): """Indicates that transmissions to the remote end are complete. Returns: True if the operation has terminated or False if the operation remains ongoing. """ raise NotImplementedError() @abc.abstractmethod def reception_complete(self, code, details): """Indicates that reception from the other side is complete. Args: code: An application-specific code value. details: An application-specific details value. """ raise NotImplementedError() @abc.abstractmethod def ingestion_complete(self): """Indicates that customer code ingestion of received values is complete.""" raise NotImplementedError() @abc.abstractmethod def expire(self): """Indicates that the operation must abort because it has taken too long.""" raise NotImplementedError() @abc.abstractmethod def abort(self, outcome): """Indicates that the operation must abort for the indicated reason. Args: outcome: A base.Outcome indicating operation abortion. """ raise NotImplementedError() class TransmissionManager(object): """A manager responsible for transmitting to the other end of an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def kick_off( self, group, method, timeout, protocol_options, initial_metadata, payload, completion, allowance): """Transmits the values associated with operation invocation.""" raise NotImplementedError() @abc.abstractmethod def advance(self, initial_metadata, payload, completion, allowance): """Accepts values for transmission to the other end of the operation. Args: initial_metadata: An initial metadata value to be transmitted to the other side of the operation. May only ever be non-None once. payload: A payload value. completion: A base.Completion value. May only ever be non-None in the last transmission to be made to the other side. allowance: A positive integer communicating the number of additional payloads allowed to be transmitted from the other side to this side of the operation, or None if no additional allowance is being granted in this call. """ raise NotImplementedError() @abc.abstractmethod def timeout(self, timeout): """Accepts for transmission to the other side a new timeout value. Args: timeout: A positive float used as the new timeout value for the operation to be transmitted to the other side. """ raise NotImplementedError() @abc.abstractmethod def allowance(self, allowance): """Indicates to this manager that the remote customer is allowing payloads. Args: allowance: A positive integer indicating the number of additional payloads the remote customer is allowing to be transmitted from this side of the operation. """ raise NotImplementedError() @abc.abstractmethod def remote_complete(self): """Indicates to this manager that data from the remote side is complete.""" raise NotImplementedError() @abc.abstractmethod def abort(self, outcome): """Indicates that the operation has aborted. Args: outcome: A base.Outcome for the operation. If None, indicates that the operation abortion should not be communicated to the other side of the operation. """ raise NotImplementedError() class ExpirationManager(object): """A manager responsible for aborting the operation if it runs out of time.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def change_timeout(self, timeout): """Changes the timeout allotted for the operation. Operation duration is always measure from the beginning of the operation; calling this method changes the operation's allotted time to timeout total seconds, not timeout seconds from the time of this method call. Args: timeout: A length of time in seconds to allow for the operation. """ raise NotImplementedError() @abc.abstractmethod def deadline(self): """Returns the time until which the operation is allowed to run. Returns: The time (seconds since the epoch) at which the operation will expire. """ raise NotImplementedError() @abc.abstractmethod def terminate(self): """Indicates to this manager that the operation has terminated.""" raise NotImplementedError() class ProtocolManager(object): """A manager of protocol-specific values passing through an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_protocol_receiver(self, protocol_receiver): """Registers the customer object that will receive protocol objects. Args: protocol_receiver: A base.ProtocolReceiver to which protocol objects for the operation should be passed. """ raise NotImplementedError() @abc.abstractmethod def accept_protocol_context(self, protocol_context): """Accepts the protocol context object for the operation. Args: protocol_context: An object designated for use as the protocol context of the operation, with further semantics implementation-determined. """ raise NotImplementedError() class EmissionManager(base.Operator): """A manager of values emitted by customer code.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def advance( self, initial_metadata=None, payload=None, completion=None, allowance=None): """Accepts a value emitted by customer code. This method should only be called by customer code. Args: initial_metadata: An initial metadata value emitted by the local customer to be sent to the other side of the operation. payload: A payload value emitted by the local customer to be sent to the other side of the operation. completion: A Completion value emitted by the local customer to be sent to the other side of the operation. allowance: A positive integer indicating an additional number of payloads that the local customer is willing to accept from the other side of the operation. """ raise NotImplementedError() class IngestionManager(object): """A manager responsible for executing customer code. This name of this manager comes from its responsibility to pass successive values from the other side of the operation into the code of the local customer. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_group_and_method(self, group, method): """Communicates to this IngestionManager the operation group and method. Args: group: The group identifier of the operation. method: The method identifier of the operation. """ raise NotImplementedError() @abc.abstractmethod def add_local_allowance(self, allowance): """Communicates to this IngestionManager that more payloads may be ingested. Args: allowance: A positive integer indicating an additional number of payloads that the local customer is willing to ingest. """ raise NotImplementedError() @abc.abstractmethod def local_emissions_done(self): """Indicates to this manager that local emissions are done.""" raise NotImplementedError() @abc.abstractmethod def advance(self, initial_metadata, payload, completion, allowance): """Advances the operation by passing values to the local customer.""" raise NotImplementedError() class ReceptionManager(object): """A manager responsible for receiving tickets from the other end.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def receive_ticket(self, ticket): """Handle a ticket from the other side of the operation. Args: ticket: A links.Ticket for the operation. """ raise NotImplementedError() class Operation(object): """An ongoing operation. Attributes: context: A base.OperationContext object for the operation. operator: A base.Operator object for the operation for use by the customer of the operation. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def handle_ticket(self, ticket): """Handle a ticket from the other side of the operation. Args: ticket: A links.Ticket from the other side of the operation. """ raise NotImplementedError() @abc.abstractmethod def abort(self, outcome_kind): """Aborts the operation. Args: outcome_kind: A base.Outcome.Kind value indicating operation abortion. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/core/_protocol.py0000644000175000017500000001560412600663151024552 0ustar apollockapollock# 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. """State and behavior for passing protocol objects in an operation.""" import collections import enum from grpc.framework.core import _constants from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.foundation import callable_util from grpc.framework.interfaces.base import base _EXCEPTION_LOG_MESSAGE = 'Exception delivering protocol object!' _LOCAL_FAILURE_OUTCOME = _utilities.Outcome( base.Outcome.Kind.LOCAL_FAILURE, None, None) class _Awaited( collections.namedtuple('_Awaited', ('kind', 'value',))): @enum.unique class Kind(enum.Enum): NOT_YET_ARRIVED = 'not yet arrived' ARRIVED = 'arrived' _NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None) _ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None) class _Transitory( collections.namedtuple('_Transitory', ('kind', 'value',))): @enum.unique class Kind(enum.Enum): NOT_YET_SEEN = 'not yet seen' PRESENT = 'present' GONE = 'gone' _NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None) _GONE = _Transitory(_Transitory.Kind.GONE, None) class _ProtocolManager(_interfaces.ProtocolManager): """An implementation of _interfaces.ExpirationManager.""" def __init__( self, protocol_receiver, lock, pool, termination_manager, transmission_manager, expiration_manager): """Constructor. Args: protocol_receiver: An _Awaited wrapping of the base.ProtocolReceiver to which protocol objects should be passed during the operation. May be of kind _Awaited.Kind.NOT_YET_ARRIVED if the customer's subscription is not yet known and may be of kind _Awaited.Kind.ARRIVED but with a value of None if the customer's subscription did not include a ProtocolReceiver. lock: The operation-wide lock. pool: A thread pool. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ self._lock = lock self._pool = pool self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = expiration_manager self._protocol_receiver = protocol_receiver self._context = _NOT_YET_SEEN def _abort_and_notify(self, outcome): if self._termination_manager.outcome is None: self._termination_manager.abort(outcome) self._transmission_manager.abort(outcome) self._expiration_manager.terminate() def _deliver(self, behavior, value): def deliver(): delivery_outcome = callable_util.call_logging_exceptions( behavior, _EXCEPTION_LOG_MESSAGE, value) if delivery_outcome.kind is callable_util.Outcome.Kind.RAISED: with self._lock: self._abort_and_notify(_LOCAL_FAILURE_OUTCOME) self._pool.submit( callable_util.with_exceptions_logged( deliver, _constants.INTERNAL_ERROR_LOG_MESSAGE)) def set_protocol_receiver(self, protocol_receiver): """See _interfaces.ProtocolManager.set_protocol_receiver for spec.""" self._protocol_receiver = _Awaited(_Awaited.Kind.ARRIVED, protocol_receiver) if (self._context.kind is _Transitory.Kind.PRESENT and protocol_receiver is not None): self._deliver(protocol_receiver.context, self._context.value) self._context = _GONE def accept_protocol_context(self, protocol_context): """See _interfaces.ProtocolManager.accept_protocol_context for spec.""" if self._protocol_receiver.kind is _Awaited.Kind.ARRIVED: if self._protocol_receiver.value is not None: self._deliver(self._protocol_receiver.value.context, protocol_context) self._context = _GONE else: self._context = _Transitory(_Transitory.Kind.PRESENT, protocol_context) def invocation_protocol_manager( subscription, lock, pool, termination_manager, transmission_manager, expiration_manager): """Creates an _interfaces.ProtocolManager for invocation-side use. Args: subscription: The local customer's subscription to the operation. lock: The operation-wide lock. pool: A thread pool. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ if subscription.kind is base.Subscription.Kind.FULL: awaited_protocol_receiver = _Awaited( _Awaited.Kind.ARRIVED, subscription.protocol_receiver) else: awaited_protocol_receiver = _ARRIVED_AND_NONE return _ProtocolManager( awaited_protocol_receiver, lock, pool, termination_manager, transmission_manager, expiration_manager) def service_protocol_manager( lock, pool, termination_manager, transmission_manager, expiration_manager): """Creates an _interfaces.ProtocolManager for service-side use. Args: lock: The operation-wide lock. pool: A thread pool. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ return _ProtocolManager( _NOT_YET_ARRIVED, lock, pool, termination_manager, transmission_manager, expiration_manager) grpc-0.11.1/src/python/grpcio/grpc/framework/core/_operation.py0000644000175000017500000002217112600663151024706 0ustar apollockapollock# 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. """Implementation of operations.""" import threading from grpc.framework.core import _context from grpc.framework.core import _emission from grpc.framework.core import _expiration from grpc.framework.core import _ingestion from grpc.framework.core import _interfaces from grpc.framework.core import _protocol from grpc.framework.core import _reception from grpc.framework.core import _termination from grpc.framework.core import _transmission from grpc.framework.core import _utilities class _EasyOperation(_interfaces.Operation): """A trivial implementation of interfaces.Operation.""" def __init__( self, lock, termination_manager, transmission_manager, expiration_manager, context, operator, reception_manager): """Constructor. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. context: A base.OperationContext for use by the customer during the operation. operator: A base.Operator for use by the customer during the operation. reception_manager: The _interfaces.ReceptionManager for the operation. """ self._lock = lock self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = expiration_manager self._reception_manager = reception_manager self.context = context self.operator = operator def handle_ticket(self, ticket): with self._lock: self._reception_manager.receive_ticket(ticket) def abort(self, outcome_kind): with self._lock: if self._termination_manager.outcome is None: outcome = _utilities.Outcome(outcome_kind, None, None) self._termination_manager.abort(outcome) self._transmission_manager.abort(outcome) self._expiration_manager.terminate() def invocation_operate( operation_id, group, method, subscription, timeout, protocol_options, initial_metadata, payload, completion, ticket_sink, termination_action, pool): """Constructs objects necessary for front-side operation management. Args: operation_id: An object identifying the operation. group: The group identifier of the operation. method: The method identifier of the operation. subscription: A base.Subscription describing the customer's interest in the results of the operation. timeout: A length of time in seconds to allow for the operation. protocol_options: A transport-specific, application-specific, and/or protocol-specific value relating to the invocation. May be None. initial_metadata: An initial metadata value to be sent to the other side of the operation. May be None if the initial metadata will be passed later or if there will be no initial metadata passed at all. payload: The first payload value to be transmitted to the other side. May be None if there is no such value or if the customer chose not to pass it at operation invocation. completion: A base.Completion value indicating the end of values passed to the other side of the operation. ticket_sink: A callable that accepts links.Tickets and delivers them to the other side of the operation. termination_action: A callable that accepts the outcome of the operation as a base.Outcome value to be called on operation completion. pool: A thread pool with which to do the work of the operation. Returns: An _interfaces.Operation for the operation. """ lock = threading.Lock() with lock: termination_manager = _termination.invocation_termination_manager( termination_action, pool) transmission_manager = _transmission.TransmissionManager( operation_id, ticket_sink, lock, pool, termination_manager) expiration_manager = _expiration.invocation_expiration_manager( timeout, lock, termination_manager, transmission_manager) protocol_manager = _protocol.invocation_protocol_manager( subscription, lock, pool, termination_manager, transmission_manager, expiration_manager) operation_context = _context.OperationContext( lock, termination_manager, transmission_manager, expiration_manager) emission_manager = _emission.EmissionManager( lock, termination_manager, transmission_manager, expiration_manager) ingestion_manager = _ingestion.invocation_ingestion_manager( subscription, lock, pool, termination_manager, transmission_manager, expiration_manager, protocol_manager) reception_manager = _reception.ReceptionManager( termination_manager, transmission_manager, expiration_manager, protocol_manager, ingestion_manager) termination_manager.set_expiration_manager(expiration_manager) transmission_manager.set_expiration_manager(expiration_manager) emission_manager.set_ingestion_manager(ingestion_manager) transmission_manager.kick_off( group, method, timeout, protocol_options, initial_metadata, payload, completion, None) return _EasyOperation( lock, termination_manager, transmission_manager, expiration_manager, operation_context, emission_manager, reception_manager) def service_operate( servicer_package, ticket, ticket_sink, termination_action, pool): """Constructs an Operation for service of an operation. Args: servicer_package: A _utilities.ServicerPackage to be used servicing the operation. ticket: The first links.Ticket received for the operation. ticket_sink: A callable that accepts links.Tickets and delivers them to the other side of the operation. termination_action: A callable that accepts the outcome of the operation as a base.Outcome value to be called on operation completion. pool: A thread pool with which to do the work of the operation. Returns: An _interfaces.Operation for the operation. """ lock = threading.Lock() with lock: termination_manager = _termination.service_termination_manager( termination_action, pool) transmission_manager = _transmission.TransmissionManager( ticket.operation_id, ticket_sink, lock, pool, termination_manager) expiration_manager = _expiration.service_expiration_manager( ticket.timeout, servicer_package.default_timeout, servicer_package.maximum_timeout, lock, termination_manager, transmission_manager) protocol_manager = _protocol.service_protocol_manager( lock, pool, termination_manager, transmission_manager, expiration_manager) operation_context = _context.OperationContext( lock, termination_manager, transmission_manager, expiration_manager) emission_manager = _emission.EmissionManager( lock, termination_manager, transmission_manager, expiration_manager) ingestion_manager = _ingestion.service_ingestion_manager( servicer_package.servicer, operation_context, emission_manager, lock, pool, termination_manager, transmission_manager, expiration_manager, protocol_manager) reception_manager = _reception.ReceptionManager( termination_manager, transmission_manager, expiration_manager, protocol_manager, ingestion_manager) termination_manager.set_expiration_manager(expiration_manager) transmission_manager.set_expiration_manager(expiration_manager) emission_manager.set_ingestion_manager(ingestion_manager) reception_manager.receive_ticket(ticket) return _EasyOperation( lock, termination_manager, transmission_manager, expiration_manager, operation_context, emission_manager, reception_manager) grpc-0.11.1/src/python/grpcio/grpc/framework/core/_transmission.py0000644000175000017500000003154312600663151025442 0ustar apollockapollock# 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. """State and behavior for ticket transmission during an operation.""" import collections import enum from grpc.framework.core import _constants from grpc.framework.core import _interfaces from grpc.framework.core import _utilities from grpc.framework.foundation import callable_util from grpc.framework.interfaces.base import base from grpc.framework.interfaces.links import links _TRANSMISSION_EXCEPTION_LOG_MESSAGE = 'Exception during transmission!' _TRANSMISSION_FAILURE_OUTCOME = _utilities.Outcome( base.Outcome.Kind.TRANSMISSION_FAILURE, None, None) def _explode_completion(completion): if completion is None: return None, None, None, None else: return ( completion.terminal_metadata, completion.code, completion.message, links.Ticket.Termination.COMPLETION) class _Abort( collections.namedtuple( '_Abort', ('kind', 'termination', 'code', 'details',))): """Tracks whether the operation aborted and what is to be done about it. Attributes: kind: A Kind value describing the overall kind of the _Abort. termination: A links.Ticket.Termination value to be sent to the other side of the operation. Only valid if kind is Kind.ABORTED_NOTIFY_NEEDED. code: A code value to be sent to the other side of the operation. Only valid if kind is Kind.ABORTED_NOTIFY_NEEDED. details: A details value to be sent to the other side of the operation. Only valid if kind is Kind.ABORTED_NOTIFY_NEEDED. """ @enum.unique class Kind(enum.Enum): NOT_ABORTED = 'not aborted' ABORTED_NOTIFY_NEEDED = 'aborted notify needed' ABORTED_NO_NOTIFY = 'aborted no notify' _NOT_ABORTED = _Abort(_Abort.Kind.NOT_ABORTED, None, None, None) _ABORTED_NO_NOTIFY = _Abort(_Abort.Kind.ABORTED_NO_NOTIFY, None, None, None) class TransmissionManager(_interfaces.TransmissionManager): """An _interfaces.TransmissionManager that sends links.Tickets.""" def __init__( self, operation_id, ticket_sink, lock, pool, termination_manager): """Constructor. Args: operation_id: The operation's ID. ticket_sink: A callable that accepts tickets and sends them to the other side of the operation. lock: The operation-servicing-wide lock object. pool: A thread pool in which the work of transmitting tickets will be performed. termination_manager: The _interfaces.TerminationManager associated with this operation. """ self._lock = lock self._pool = pool self._ticket_sink = ticket_sink self._operation_id = operation_id self._termination_manager = termination_manager self._expiration_manager = None self._lowest_unused_sequence_number = 0 self._remote_allowance = 1 self._remote_complete = False self._timeout = None self._local_allowance = 0 self._initial_metadata = None self._payloads = [] self._completion = None self._abort = _NOT_ABORTED self._transmitting = False def set_expiration_manager(self, expiration_manager): """Sets the ExpirationManager with which this manager will cooperate.""" self._expiration_manager = expiration_manager def _next_ticket(self): """Creates the next ticket to be transmitted. Returns: A links.Ticket to be sent to the other side of the operation or None if there is nothing to be sent at this time. """ if self._abort.kind is _Abort.Kind.ABORTED_NO_NOTIFY: return None elif self._abort.kind is _Abort.Kind.ABORTED_NOTIFY_NEEDED: termination = self._abort.termination code, details = self._abort.code, self._abort.details self._abort = _ABORTED_NO_NOTIFY return links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, None, None, None, None, None, None, None, code, details, termination, None) action = False # TODO(nathaniel): Support other subscriptions. local_subscription = links.Ticket.Subscription.FULL timeout = self._timeout if timeout is not None: self._timeout = None action = True if self._local_allowance <= 0: allowance = None else: allowance = self._local_allowance self._local_allowance = 0 action = True initial_metadata = self._initial_metadata if initial_metadata is not None: self._initial_metadata = None action = True if not self._payloads or self._remote_allowance <= 0: payload = None else: payload = self._payloads.pop(0) self._remote_allowance -= 1 action = True if self._completion is None or self._payloads: terminal_metadata, code, message, termination = None, None, None, None else: terminal_metadata, code, message, termination = _explode_completion( self._completion) self._completion = None action = True if action: ticket = links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, None, local_subscription, timeout, allowance, initial_metadata, payload, terminal_metadata, code, message, termination, None) self._lowest_unused_sequence_number += 1 return ticket else: return None def _transmit(self, ticket): """Commences the transmission loop sending tickets. Args: ticket: A links.Ticket to be sent to the other side of the operation. """ def transmit(ticket): while True: transmission_outcome = callable_util.call_logging_exceptions( self._ticket_sink, _TRANSMISSION_EXCEPTION_LOG_MESSAGE, ticket) if transmission_outcome.exception is None: with self._lock: if ticket.termination is links.Ticket.Termination.COMPLETION: self._termination_manager.transmission_complete() ticket = self._next_ticket() if ticket is None: self._transmitting = False return else: with self._lock: self._abort = _ABORTED_NO_NOTIFY if self._termination_manager.outcome is None: self._termination_manager.abort(_TRANSMISSION_FAILURE_OUTCOME) self._expiration_manager.terminate() return self._pool.submit(callable_util.with_exceptions_logged( transmit, _constants.INTERNAL_ERROR_LOG_MESSAGE), ticket) self._transmitting = True def kick_off( self, group, method, timeout, protocol_options, initial_metadata, payload, completion, allowance): """See _interfaces.TransmissionManager.kickoff for specification.""" # TODO(nathaniel): Support other subscriptions. subscription = links.Ticket.Subscription.FULL terminal_metadata, code, message, termination = _explode_completion( completion) self._remote_allowance = 1 if payload is None else 0 protocol = links.Protocol(links.Protocol.Kind.CALL_OPTION, protocol_options) ticket = links.Ticket( self._operation_id, 0, group, method, subscription, timeout, allowance, initial_metadata, payload, terminal_metadata, code, message, termination, protocol) self._lowest_unused_sequence_number = 1 self._transmit(ticket) def advance(self, initial_metadata, payload, completion, allowance): """See _interfaces.TransmissionManager.advance for specification.""" if self._abort.kind is not _Abort.Kind.NOT_ABORTED: return effective_initial_metadata = initial_metadata effective_payload = payload effective_completion = completion if allowance is not None and not self._remote_complete: effective_allowance = allowance else: effective_allowance = None if self._transmitting: if effective_initial_metadata is not None: self._initial_metadata = effective_initial_metadata if effective_payload is not None: self._payloads.append(effective_payload) if effective_completion is not None: self._completion = effective_completion if effective_allowance is not None: self._local_allowance += effective_allowance else: if effective_payload is not None: if 0 < self._remote_allowance: ticket_payload = effective_payload self._remote_allowance -= 1 else: self._payloads.append(effective_payload) ticket_payload = None else: ticket_payload = None if effective_completion is not None and not self._payloads: ticket_completion = effective_completion else: self._completion = effective_completion ticket_completion = None if any( (effective_initial_metadata, ticket_payload, ticket_completion, effective_allowance)): terminal_metadata, code, message, termination = _explode_completion( completion) ticket = links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, None, None, None, allowance, effective_initial_metadata, ticket_payload, terminal_metadata, code, message, termination, None) self._lowest_unused_sequence_number += 1 self._transmit(ticket) def timeout(self, timeout): """See _interfaces.TransmissionManager.timeout for specification.""" if self._abort.kind is not _Abort.Kind.NOT_ABORTED: return elif self._transmitting: self._timeout = timeout else: ticket = links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, None, None, timeout, None, None, None, None, None, None, None, None) self._lowest_unused_sequence_number += 1 self._transmit(ticket) def allowance(self, allowance): """See _interfaces.TransmissionManager.allowance for specification.""" if self._abort.kind is not _Abort.Kind.NOT_ABORTED: return elif self._transmitting or not self._payloads: self._remote_allowance += allowance else: self._remote_allowance += allowance - 1 payload = self._payloads.pop(0) if self._payloads: completion = None else: completion = self._completion self._completion = None terminal_metadata, code, message, termination = _explode_completion( completion) ticket = links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, None, None, None, None, None, payload, terminal_metadata, code, message, termination, None) self._lowest_unused_sequence_number += 1 self._transmit(ticket) def remote_complete(self): """See _interfaces.TransmissionManager.remote_complete for specification.""" self._remote_complete = True self._local_allowance = 0 def abort(self, outcome): """See _interfaces.TransmissionManager.abort for specification.""" if self._abort.kind is _Abort.Kind.NOT_ABORTED: if outcome is None: self._abort = _ABORTED_NO_NOTIFY else: termination = _constants.ABORTION_OUTCOME_TO_TICKET_TERMINATION.get( outcome.kind) if termination is None: self._abort = _ABORTED_NO_NOTIFY elif self._transmitting: self._abort = _Abort( _Abort.Kind.ABORTED_NOTIFY_NEEDED, termination, outcome.code, outcome.details) else: ticket = links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, None, None, None, None, None, None, None, outcome.code, outcome.details, termination, None) self._transmit(ticket) self._abort = _ABORTED_NO_NOTIFY grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/0000755000175000017500000000000012600663151023365 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/links/0000755000175000017500000000000012600663151024505 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/links/utilities.py0000644000175000017500000000342212600663151027073 0ustar apollockapollock# 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. """Utilities provided as part of the links interface.""" from grpc.framework.interfaces.links import links class _NullLink(links.Link): """A do-nothing links.Link.""" def accept_ticket(self, ticket): pass def join_link(self, link): pass NULL_LINK = _NullLink() grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/links/__init__.py0000644000175000017500000000277212600663151026626 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/links/links.py0000644000175000017500000001412312600663151026200 0ustar apollockapollock# 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. """The low-level ticket-exchanging-links interface of RPC Framework.""" import abc import collections import enum class Protocol(collections.namedtuple('Protocol', ('kind', 'value',))): """A sum type for handles to a system that transmits tickets. Attributes: kind: A Kind value identifying the kind of value being passed. value: The value being passed between the high-level application and the system affording ticket transport. """ @enum.unique class Kind(enum.Enum): CALL_OPTION = 'call option' SERVICER_CONTEXT = 'servicer context' INVOCATION_CONTEXT = 'invocation context' class Ticket( collections.namedtuple( 'Ticket', ('operation_id', 'sequence_number', 'group', 'method', 'subscription', 'timeout', 'allowance', 'initial_metadata', 'payload', 'terminal_metadata', 'code', 'message', 'termination', 'protocol',))): """A sum type for all values sent from a front to a back. Attributes: operation_id: A unique-with-respect-to-equality hashable object identifying a particular operation. sequence_number: A zero-indexed integer sequence number identifying the ticket's place in the stream of tickets sent in one direction for the particular operation. group: The group to which the method of the operation belongs. Must be present in the first ticket from invocation side to service side. Ignored for all other tickets exchanged during the operation. method: The name of an operation. Must be present in the first ticket from invocation side to service side. Ignored for all other tickets exchanged during the operation. subscription: A Subscription value describing the interest one side has in receiving information from the other side. Must be present in the first ticket from either side. Ignored for all other tickets exchanged during the operation. timeout: A nonzero length of time (measured from the beginning of the operation) to allow for the entire operation. Must be present in the first ticket from invocation side to service side. Optional for all other tickets exchanged during the operation. Receipt of a value from the other side of the operation indicates the value in use by that side. Setting a value on a later ticket allows either side to request time extensions (or even time reductions!) on in-progress operations. allowance: A positive integer granting permission for a number of payloads to be transmitted to the communicating side of the operation, or None if no additional allowance is being granted with this ticket. initial_metadata: An optional metadata value communicated from one side to the other at the beginning of the operation. May be non-None in at most one ticket from each side. Any non-None value must appear no later than the first payload value. payload: A customer payload object. May be None. terminal_metadata: A metadata value comminicated from one side to the other at the end of the operation. May be non-None in the same ticket as the code and message, but must be None for all earlier tickets. code: A value communicated at operation completion. May be None. message: A value communicated at operation completion. May be None. termination: A Termination value describing the end of the operation, or None if the operation has not yet terminated. If set, no further tickets may be sent in the same direction. protocol: A Protocol value or None, with further semantics being a matter between high-level application and underlying ticket transport. """ @enum.unique class Subscription(enum.Enum): """Identifies the level of subscription of a side of an operation.""" NONE = 'none' TERMINATION = 'termination' FULL = 'full' @enum.unique class Termination(enum.Enum): """Identifies the termination of an operation.""" COMPLETION = 'completion' CANCELLATION = 'cancellation' EXPIRATION = 'expiration' SHUTDOWN = 'shutdown' RECEPTION_FAILURE = 'reception failure' TRANSMISSION_FAILURE = 'transmission failure' LOCAL_FAILURE = 'local failure' REMOTE_FAILURE = 'remote failure' class Link(object): """Accepts and emits tickets.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def accept_ticket(self, ticket): """Accept a Ticket. Args: ticket: Any Ticket. """ raise NotImplementedError() @abc.abstractmethod def join_link(self, link): """Mates this object with a peer with which it will exchange tickets.""" raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/face/0000755000175000017500000000000012600663151024263 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/face/utilities.py0000644000175000017500000001532712600663151026660 0ustar apollockapollock# 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. """Utilities for RPC Framework's Face interface.""" import collections # stream is referenced from specification in this module. from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.foundation import stream # pylint: disable=unused-import from grpc.framework.interfaces.face import face class _MethodImplementation( face.MethodImplementation, collections.namedtuple( '_MethodImplementation', ['cardinality', 'style', 'unary_unary_inline', 'unary_stream_inline', 'stream_unary_inline', 'stream_stream_inline', 'unary_unary_event', 'unary_stream_event', 'stream_unary_event', 'stream_stream_event',])): pass def unary_unary_inline(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-unary RPC method as a callable value that takes a request value and an face.ServicerContext object and returns a response value. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_UNARY, style.Service.INLINE, behavior, None, None, None, None, None, None, None) def unary_stream_inline(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-stream RPC method as a callable value that takes a request value and an face.ServicerContext object and returns an iterator of response values. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_STREAM, style.Service.INLINE, None, behavior, None, None, None, None, None, None) def stream_unary_inline(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-unary RPC method as a callable value that takes an iterator of request values and an face.ServicerContext object and returns a response value. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_UNARY, style.Service.INLINE, None, None, behavior, None, None, None, None, None) def stream_stream_inline(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-stream RPC method as a callable value that takes an iterator of request values and an face.ServicerContext object and returns an iterator of response values. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_STREAM, style.Service.INLINE, None, None, None, behavior, None, None, None, None) def unary_unary_event(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-unary RPC method as a callable value that takes a request value, a response callback to which to pass the response value of the RPC, and an face.ServicerContext. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_UNARY, style.Service.EVENT, None, None, None, None, behavior, None, None, None) def unary_stream_event(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-stream RPC method as a callable value that takes a request value, a stream.Consumer to which to pass the the response values of the RPC, and an face.ServicerContext. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_STREAM, style.Service.EVENT, None, None, None, None, None, behavior, None, None) def stream_unary_event(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-unary RPC method as a callable value that takes a response callback to which to pass the response value of the RPC and an face.ServicerContext and returns a stream.Consumer to which the request values of the RPC should be passed. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_UNARY, style.Service.EVENT, None, None, None, None, None, None, behavior, None) def stream_stream_event(behavior): """Creates an face.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-stream RPC method as a callable value that takes a stream.Consumer to which to pass the response values of the RPC and an face.ServicerContext and returns a stream.Consumer to which the request values of the RPC should be passed. Returns: An face.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_STREAM, style.Service.EVENT, None, None, None, None, None, None, None, behavior) grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/face/face.py0000644000175000017500000011114612600663151025537 0ustar apollockapollock# 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. """Interfaces defining the Face layer of RPC Framework.""" import abc import collections import enum # cardinality, style, abandonment, future, and stream are # referenced from specification in this module. from grpc.framework.common import cardinality # pylint: disable=unused-import from grpc.framework.common import style # pylint: disable=unused-import from grpc.framework.foundation import abandonment # pylint: disable=unused-import from grpc.framework.foundation import future # pylint: disable=unused-import from grpc.framework.foundation import stream # pylint: disable=unused-import class NoSuchMethodError(Exception): """Raised by customer code to indicate an unrecognized method. Attributes: group: The group of the unrecognized method. name: The name of the unrecognized method. """ def __init__(self, group, method): """Constructor. Args: group: The group identifier of the unrecognized RPC name. method: The method identifier of the unrecognized RPC name. """ super(NoSuchMethodError, self).__init__() self.group = group self.method = method def __repr__(self): return 'face.NoSuchMethodError(%s, %s)' % (self.group, self.method,) class Abortion( collections.namedtuple( 'Abortion', ('kind', 'initial_metadata', 'terminal_metadata', 'code', 'details',))): """A value describing RPC abortion. Attributes: kind: A Kind value identifying how the RPC failed. initial_metadata: The initial metadata from the other side of the RPC or None if no initial metadata value was received. terminal_metadata: The terminal metadata from the other side of the RPC or None if no terminal metadata value was received. code: The code value from the other side of the RPC or None if no code value was received. details: The details value from the other side of the RPC or None if no details value was received. """ @enum.unique class Kind(enum.Enum): """Types of RPC abortion.""" CANCELLED = 'cancelled' EXPIRED = 'expired' LOCAL_SHUTDOWN = 'local shutdown' REMOTE_SHUTDOWN = 'remote shutdown' NETWORK_FAILURE = 'network failure' LOCAL_FAILURE = 'local failure' REMOTE_FAILURE = 'remote failure' class AbortionError(Exception): """Common super type for exceptions indicating RPC abortion. initial_metadata: The initial metadata from the other side of the RPC or None if no initial metadata value was received. terminal_metadata: The terminal metadata from the other side of the RPC or None if no terminal metadata value was received. code: The code value from the other side of the RPC or None if no code value was received. details: The details value from the other side of the RPC or None if no details value was received. """ __metaclass__ = abc.ABCMeta def __init__(self, initial_metadata, terminal_metadata, code, details): super(AbortionError, self).__init__() self.initial_metadata = initial_metadata self.terminal_metadata = terminal_metadata self.code = code self.details = details class CancellationError(AbortionError): """Indicates that an RPC has been cancelled.""" class ExpirationError(AbortionError): """Indicates that an RPC has expired ("timed out").""" class LocalShutdownError(AbortionError): """Indicates that an RPC has terminated due to local shutdown of RPCs.""" class RemoteShutdownError(AbortionError): """Indicates that an RPC has terminated due to remote shutdown of RPCs.""" class NetworkError(AbortionError): """Indicates that some error occurred on the network.""" class LocalError(AbortionError): """Indicates that an RPC has terminated due to a local defect.""" class RemoteError(AbortionError): """Indicates that an RPC has terminated due to a remote defect.""" class RpcContext(object): """Provides RPC-related information and action.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): """Describes whether the RPC is active or has terminated.""" raise NotImplementedError() @abc.abstractmethod def time_remaining(self): """Describes the length of allowed time remaining for the RPC. Returns: A nonnegative float indicating the length of allowed time in seconds remaining for the RPC to complete before it is considered to have timed out. """ raise NotImplementedError() @abc.abstractmethod def add_abortion_callback(self, abortion_callback): """Registers a callback to be called if the RPC is aborted. Args: abortion_callback: A callable to be called and passed an Abortion value in the event of RPC abortion. """ raise NotImplementedError() @abc.abstractmethod def cancel(self): """Cancels the RPC. Idempotent and has no effect if the RPC has already terminated. """ raise NotImplementedError() @abc.abstractmethod def protocol_context(self): """Accesses a custom object specified by an implementation provider. Returns: A value specified by the provider of a Face interface implementation affording custom state and behavior. """ raise NotImplementedError() class Call(RpcContext): """Invocation-side utility object for an RPC.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def initial_metadata(self): """Accesses the initial metadata from the service-side of the RPC. This method blocks until the value is available or is known not to have been emitted from the service-side of the RPC. Returns: The initial metadata object emitted by the service-side of the RPC, or None if there was no such value. """ raise NotImplementedError() @abc.abstractmethod def terminal_metadata(self): """Accesses the terminal metadata from the service-side of the RPC. This method blocks until the value is available or is known not to have been emitted from the service-side of the RPC. Returns: The terminal metadata object emitted by the service-side of the RPC, or None if there was no such value. """ raise NotImplementedError() @abc.abstractmethod def code(self): """Accesses the code emitted by the service-side of the RPC. This method blocks until the value is available or is known not to have been emitted from the service-side of the RPC. Returns: The code object emitted by the service-side of the RPC, or None if there was no such value. """ raise NotImplementedError() @abc.abstractmethod def details(self): """Accesses the details value emitted by the service-side of the RPC. This method blocks until the value is available or is known not to have been emitted from the service-side of the RPC. Returns: The details value emitted by the service-side of the RPC, or None if there was no such value. """ raise NotImplementedError() class ServicerContext(RpcContext): """A context object passed to method implementations.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def invocation_metadata(self): """Accesses the metadata from the invocation-side of the RPC. This method blocks until the value is available or is known not to have been emitted from the invocation-side of the RPC. Returns: The metadata object emitted by the invocation-side of the RPC, or None if there was no such value. """ raise NotImplementedError() @abc.abstractmethod def initial_metadata(self, initial_metadata): """Accepts the service-side initial metadata value of the RPC. This method need not be called by method implementations if they have no service-side initial metadata to transmit. Args: initial_metadata: The service-side initial metadata value of the RPC to be transmitted to the invocation side of the RPC. """ raise NotImplementedError() @abc.abstractmethod def terminal_metadata(self, terminal_metadata): """Accepts the service-side terminal metadata value of the RPC. This method need not be called by method implementations if they have no service-side terminal metadata to transmit. Args: terminal_metadata: The service-side terminal metadata value of the RPC to be transmitted to the invocation side of the RPC. """ raise NotImplementedError() @abc.abstractmethod def code(self, code): """Accepts the service-side code of the RPC. This method need not be called by method implementations if they have no code to transmit. Args: code: The code of the RPC to be transmitted to the invocation side of the RPC. """ raise NotImplementedError() @abc.abstractmethod def details(self, details): """Accepts the service-side details of the RPC. This method need not be called by method implementations if they have no service-side details to transmit. Args: details: The service-side details value of the RPC to be transmitted to the invocation side of the RPC. """ raise NotImplementedError() class ResponseReceiver(object): """Invocation-side object used to accept the output of an RPC.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def initial_metadata(self, initial_metadata): """Receives the initial metadata from the service-side of the RPC. Args: initial_metadata: The initial metadata object emitted from the service-side of the RPC. """ raise NotImplementedError() @abc.abstractmethod def response(self, response): """Receives a response from the service-side of the RPC. Args: response: A response object emitted from the service-side of the RPC. """ raise NotImplementedError() @abc.abstractmethod def complete(self, terminal_metadata, code, details): """Receives the completion values emitted from the service-side of the RPC. Args: terminal_metadata: The terminal metadata object emitted from the service-side of the RPC. code: The code object emitted from the service-side of the RPC. details: The details object emitted from the service-side of the RPC. """ raise NotImplementedError() class UnaryUnaryMultiCallable(object): """Affords invoking a unary-unary RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__( self, request, timeout, metadata=None, with_call=False, protocol_options=None): """Synchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. with_call: Whether or not to include return a Call for the RPC in addition to the reponse. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: The response value for the RPC, and a Call for the RPC if with_call was set to True at invocation. Raises: AbortionError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future(self, request, timeout, metadata=None, protocol_options=None): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and a future.Future. In the event of RPC completion, the return Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an AbortionError. """ raise NotImplementedError() @abc.abstractmethod def event( self, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A Call for the RPC. """ raise NotImplementedError() class UnaryStreamMultiCallable(object): """Affords invoking a unary-stream RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout, metadata=None, protocol_options=None): """Invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and an iterator of response values. Drawing response values from the returned iterator may raise AbortionError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def event( self, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A Call object for the RPC. """ raise NotImplementedError() class StreamUnaryMultiCallable(object): """Affords invoking a stream-unary RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__( self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None): """Synchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. with_call: Whether or not to include return a Call for the RPC in addition to the reponse. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: The response value for the RPC, and a Call for the RPC if with_call was set to True at invocation. Raises: AbortionError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future( self, request_iterator, timeout, metadata=None, protocol_options=None): """Asynchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and a future.Future. In the event of RPC completion, the return Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an AbortionError. """ raise NotImplementedError() @abc.abstractmethod def event( self, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Asynchronously invokes the underlying RPC. Args: receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A single object that is both a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() class StreamStreamMultiCallable(object): """Affords invoking a stream-stream RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__( self, request_iterator, timeout, metadata=None, protocol_options=None): """Invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and an iterator of response values. Drawing response values from the returned iterator may raise AbortionError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def event( self, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Asynchronously invokes the underlying RPC. Args: receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A single object that is both a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() class MethodImplementation(object): """A sum type that describes a method implementation. Attributes: cardinality: A cardinality.Cardinality value. style: A style.Service value. unary_unary_inline: The implementation of the method as a callable value that takes a request value and a ServicerContext object and returns a response value. Only non-None if cardinality is cardinality.Cardinality.UNARY_UNARY and style is style.Service.INLINE. unary_stream_inline: The implementation of the method as a callable value that takes a request value and a ServicerContext object and returns an iterator of response values. Only non-None if cardinality is cardinality.Cardinality.UNARY_STREAM and style is style.Service.INLINE. stream_unary_inline: The implementation of the method as a callable value that takes an iterator of request values and a ServicerContext object and returns a response value. Only non-None if cardinality is cardinality.Cardinality.STREAM_UNARY and style is style.Service.INLINE. stream_stream_inline: The implementation of the method as a callable value that takes an iterator of request values and a ServicerContext object and returns an iterator of response values. Only non-None if cardinality is cardinality.Cardinality.STREAM_STREAM and style is style.Service.INLINE. unary_unary_event: The implementation of the method as a callable value that takes a request value, a response callback to which to pass the response value of the RPC, and a ServicerContext. Only non-None if cardinality is cardinality.Cardinality.UNARY_UNARY and style is style.Service.EVENT. unary_stream_event: The implementation of the method as a callable value that takes a request value, a stream.Consumer to which to pass the response values of the RPC, and a ServicerContext. Only non-None if cardinality is cardinality.Cardinality.UNARY_STREAM and style is style.Service.EVENT. stream_unary_event: The implementation of the method as a callable value that takes a response callback to which to pass the response value of the RPC and a ServicerContext and returns a stream.Consumer to which the request values of the RPC should be passed. Only non-None if cardinality is cardinality.Cardinality.STREAM_UNARY and style is style.Service.EVENT. stream_stream_event: The implementation of the method as a callable value that takes a stream.Consumer to which to pass the response values of the RPC and a ServicerContext and returns a stream.Consumer to which the request values of the RPC should be passed. Only non-None if cardinality is cardinality.Cardinality.STREAM_STREAM and style is style.Service.EVENT. """ __metaclass__ = abc.ABCMeta class MultiMethodImplementation(object): """A general type able to service many methods.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, group, method, response_consumer, context): """Services an RPC. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. response_consumer: A stream.Consumer to be called to accept the response values of the RPC. context: a ServicerContext object. Returns: A stream.Consumer with which to accept the request values of the RPC. The consumer returned from this method may or may not be invoked to completion: in the case of RPC abortion, RPC Framework will simply stop passing values to this object. Implementations must not assume that this object will be called to completion of the request stream or even called at all. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. NoSuchMethodError: If this MultiMethod does not recognize the given group and name for the RPC and is not able to service the RPC. """ raise NotImplementedError() class GenericStub(object): """Affords RPC invocation via generic methods.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def blocking_unary_unary( self, group, method, request, timeout, metadata=None, with_call=False, protocol_options=None): """Invokes a unary-request-unary-response method. This method blocks until either returning the response value of the RPC (in the event of RPC completion) or raising an exception (in the event of RPC abortion). Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. with_call: Whether or not to include return a Call for the RPC in addition to the reponse. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: The response value for the RPC, and a Call for the RPC if with_call was set to True at invocation. Raises: AbortionError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future_unary_unary( self, group, method, request, timeout, metadata=None, protocol_options=None): """Invokes a unary-request-unary-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and a future.Future. In the event of RPC completion, the return Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an AbortionError. """ raise NotImplementedError() @abc.abstractmethod def inline_unary_stream( self, group, method, request, timeout, metadata=None, protocol_options=None): """Invokes a unary-request-stream-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and an iterator of response values. Drawing response values from the returned iterator may raise AbortionError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def blocking_stream_unary( self, group, method, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None): """Invokes a stream-request-unary-response method. This method blocks until either returning the response value of the RPC (in the event of RPC completion) or raising an exception (in the event of RPC abortion). Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. with_call: Whether or not to include return a Call for the RPC in addition to the reponse. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: The response value for the RPC, and a Call for the RPC if with_call was set to True at invocation. Raises: AbortionError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future_stream_unary( self, group, method, request_iterator, timeout, metadata=None, protocol_options=None): """Invokes a stream-request-unary-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and a future.Future. In the event of RPC completion, the return Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an AbortionError. """ raise NotImplementedError() @abc.abstractmethod def inline_stream_stream( self, group, method, request_iterator, timeout, metadata=None, protocol_options=None): """Invokes a stream-request-stream-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: An object that is both a Call for the RPC and an iterator of response values. Drawing response values from the returned iterator may raise AbortionError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def event_unary_unary( self, group, method, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Event-driven invocation of a unary-request-unary-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request: The request value for the RPC. receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A Call for the RPC. """ raise NotImplementedError() @abc.abstractmethod def event_unary_stream( self, group, method, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Event-driven invocation of a unary-request-stream-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. request: The request value for the RPC. receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A Call for the RPC. """ raise NotImplementedError() @abc.abstractmethod def event_stream_unary( self, group, method, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Event-driven invocation of a unary-request-unary-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A pair of a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() @abc.abstractmethod def event_stream_stream( self, group, method, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): """Event-driven invocation of a unary-request-stream-response method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. receiver: A ResponseReceiver to be passed the response data of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. metadata: A metadata value to be passed to the service-side of the RPC. protocol_options: A value specified by the provider of a Face interface implementation affording custom state and behavior. Returns: A pair of a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() @abc.abstractmethod def unary_unary(self, group, method): """Creates a UnaryUnaryMultiCallable for a unary-unary method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. Returns: A UnaryUnaryMultiCallable value for the named unary-unary method. """ raise NotImplementedError() @abc.abstractmethod def unary_stream(self, group, method): """Creates a UnaryStreamMultiCallable for a unary-stream method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. Returns: A UnaryStreamMultiCallable value for the name unary-stream method. """ raise NotImplementedError() @abc.abstractmethod def stream_unary(self, group, method): """Creates a StreamUnaryMultiCallable for a stream-unary method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. Returns: A StreamUnaryMultiCallable value for the named stream-unary method. """ raise NotImplementedError() @abc.abstractmethod def stream_stream(self, group, method): """Creates a StreamStreamMultiCallable for a stream-stream method. Args: group: The group identifier of the RPC. method: The method identifier of the RPC. Returns: A StreamStreamMultiCallable value for the named stream-stream method. """ raise NotImplementedError() class DynamicStub(object): """Affords RPC invocation via attributes corresponding to afforded methods. Instances of this type may be scoped to a single group so that attribute access is unambiguous. Instances of this type respond to attribute access as follows: if the requested attribute is the name of a unary-unary method, the value of the attribute will be a UnaryUnaryMultiCallable with which to invoke an RPC; if the requested attribute is the name of a unary-stream method, the value of the attribute will be a UnaryStreamMultiCallable with which to invoke an RPC; if the requested attribute is the name of a stream-unary method, the value of the attribute will be a StreamUnaryMultiCallable with which to invoke an RPC; and if the requested attribute is the name of a stream-stream method, the value of the attribute will be a StreamStreamMultiCallable with which to invoke an RPC. """ __metaclass__ = abc.ABCMeta grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/face/__init__.py0000644000175000017500000000277212600663151026404 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/__init__.py0000644000175000017500000000277212600663151025506 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/base/0000755000175000017500000000000012600663151024277 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/base/utilities.py0000644000175000017500000000607512600663151026674 0ustar apollockapollock# 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. """Utilities for use with the base interface of RPC Framework.""" import collections from grpc.framework.interfaces.base import base class _Completion( base.Completion, collections.namedtuple( '_Completion', ('terminal_metadata', 'code', 'message',))): """A trivial implementation of base.Completion.""" class _Subscription( base.Subscription, collections.namedtuple( '_Subscription', ('kind', 'termination_callback', 'allowance', 'operator', 'protocol_receiver',))): """A trivial implementation of base.Subscription.""" _NONE_SUBSCRIPTION = _Subscription( base.Subscription.Kind.NONE, None, None, None, None) def completion(terminal_metadata, code, message): """Creates a base.Completion aggregating the given operation values. Args: terminal_metadata: A terminal metadata value for an operaton. code: A code value for an operation. message: A message value for an operation. Returns: A base.Completion aggregating the given operation values. """ return _Completion(terminal_metadata, code, message) def full_subscription(operator, protocol_receiver): """Creates a "full" base.Subscription for the given base.Operator. Args: operator: A base.Operator to be used in an operation. protocol_receiver: A base.ProtocolReceiver to be used in an operation. Returns: A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given base.Operator and base.ProtocolReceiver. """ return _Subscription( base.Subscription.Kind.FULL, None, None, operator, protocol_receiver) grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/base/__init__.py0000644000175000017500000000277212600663151026420 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/interfaces/base/base.py0000644000175000017500000003052512600663151025570 0ustar apollockapollock# 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. """The base interface of RPC Framework. Implementations of this interface support the conduct of "operations": exchanges between two distinct ends of an arbitrary number of data payloads and metadata such as a name for the operation, initial and terminal metadata in each direction, and flow control. These operations may be used for transfers of data, remote procedure calls, status indication, or anything else applications choose. """ # threading is referenced from specification in this module. import abc import enum import threading # pylint: disable=unused-import # abandonment is referenced from specification in this module. from grpc.framework.foundation import abandonment # pylint: disable=unused-import class NoSuchMethodError(Exception): """Indicates that an unrecognized operation has been called. Attributes: code: A code value to communicate to the other side of the operation along with indication of operation termination. May be None. details: A details value to communicate to the other side of the operation along with indication of operation termination. May be None. """ def __init__(self, code, details): """Constructor. Args: code: A code value to communicate to the other side of the operation along with indication of operation termination. May be None. details: A details value to communicate to the other side of the operation along with indication of operation termination. May be None. """ self.code = code self.details = details class Outcome(object): """The outcome of an operation. Attributes: kind: A Kind value coarsely identifying how the operation terminated. code: An application-specific code value or None if no such value was provided. details: An application-specific details value or None if no such value was provided. """ @enum.unique class Kind(enum.Enum): """Ways in which an operation can terminate.""" COMPLETED = 'completed' CANCELLED = 'cancelled' EXPIRED = 'expired' LOCAL_SHUTDOWN = 'local shutdown' REMOTE_SHUTDOWN = 'remote shutdown' RECEPTION_FAILURE = 'reception failure' TRANSMISSION_FAILURE = 'transmission failure' LOCAL_FAILURE = 'local failure' REMOTE_FAILURE = 'remote failure' class Completion(object): """An aggregate of the values exchanged upon operation completion. Attributes: terminal_metadata: A terminal metadata value for the operaton. code: A code value for the operation. message: A message value for the operation. """ __metaclass__ = abc.ABCMeta class OperationContext(object): """Provides operation-related information and action.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def outcome(self): """Indicates the operation's outcome (or that the operation is ongoing). Returns: None if the operation is still active or the Outcome value for the operation if it has terminated. """ raise NotImplementedError() @abc.abstractmethod def add_termination_callback(self, callback): """Adds a function to be called upon operation termination. Args: callback: A callable to be passed an Outcome value on operation termination. Returns: None if the operation has not yet terminated and the passed callback will later be called when it does terminate, or if the operation has already terminated an Outcome value describing the operation termination and the passed callback will not be called as a result of this method call. """ raise NotImplementedError() @abc.abstractmethod def time_remaining(self): """Describes the length of allowed time remaining for the operation. Returns: A nonnegative float indicating the length of allowed time in seconds remaining for the operation to complete before it is considered to have timed out. Zero is returned if the operation has terminated. """ raise NotImplementedError() @abc.abstractmethod def cancel(self): """Cancels the operation if the operation has not yet terminated.""" raise NotImplementedError() @abc.abstractmethod def fail(self, exception): """Indicates that the operation has failed. Args: exception: An exception germane to the operation failure. May be None. """ raise NotImplementedError() class Operator(object): """An interface through which to participate in an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def advance( self, initial_metadata=None, payload=None, completion=None, allowance=None): """Progresses the operation. Args: initial_metadata: An initial metadata value. Only one may ever be communicated in each direction for an operation, and they must be communicated no later than either the first payload or the completion. payload: A payload value. completion: A Completion value. May only ever be non-None once in either direction, and no payloads may be passed after it has been communicated. allowance: A positive integer communicating the number of additional payloads allowed to be passed by the remote side of the operation. """ raise NotImplementedError() class ProtocolReceiver(object): """A means of receiving protocol values during an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def context(self, protocol_context): """Accepts the protocol context object for the operation. Args: protocol_context: The protocol context object for the operation. """ raise NotImplementedError() class Subscription(object): """Describes customer code's interest in values from the other side. Attributes: kind: A Kind value describing the overall kind of this value. termination_callback: A callable to be passed the Outcome associated with the operation after it has terminated. Must be non-None if kind is Kind.TERMINATION_ONLY. Must be None otherwise. allowance: A callable behavior that accepts positive integers representing the number of additional payloads allowed to be passed to the other side of the operation. Must be None if kind is Kind.FULL. Must not be None otherwise. operator: An Operator to be passed values from the other side of the operation. Must be non-None if kind is Kind.FULL. Must be None otherwise. protocol_receiver: A ProtocolReceiver to be passed protocol objects as they become available during the operation. Must be non-None if kind is Kind.FULL. """ __metaclass__ = abc.ABCMeta @enum.unique class Kind(enum.Enum): NONE = 'none' TERMINATION_ONLY = 'termination only' FULL = 'full' class Servicer(object): """Interface for service implementations.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, group, method, context, output_operator): """Services an operation. Args: group: The group identifier of the operation to be serviced. method: The method identifier of the operation to be serviced. context: An OperationContext object affording contextual information and actions. output_operator: An Operator that will accept output values of the operation. Returns: A Subscription via which this object may or may not accept more values of the operation. Raises: NoSuchMethodError: If this Servicer does not handle operations with the given group and method. abandonment.Abandoned: If the operation has been aborted and there no longer is any reason to service the operation. """ raise NotImplementedError() class End(object): """Common type for entry-point objects on both sides of an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def start(self): """Starts this object's service of operations.""" raise NotImplementedError() @abc.abstractmethod def stop(self, grace): """Stops this object's service of operations. This object will refuse service of new operations as soon as this method is called but operations under way at the time of the call may be given a grace period during which they are allowed to finish. Args: grace: A duration of time in seconds to allow ongoing operations to terminate before being forcefully terminated by the stopping of this End. May be zero to terminate all ongoing operations and immediately stop. Returns: A threading.Event that will be set to indicate all operations having terminated and this End having completely stopped. The returned event may not be set until after the full grace period (if some ongoing operation continues for the full length of the period) or it may be set much sooner (if for example this End had no operations in progress at the time its stop method was called). """ raise NotImplementedError() @abc.abstractmethod def operate( self, group, method, subscription, timeout, initial_metadata=None, payload=None, completion=None, protocol_options=None): """Commences an operation. Args: group: The group identifier of the invoked operation. method: The method identifier of the invoked operation. subscription: A Subscription to which the results of the operation will be passed. timeout: A length of time in seconds to allow for the operation. initial_metadata: An initial metadata value to be sent to the other side of the operation. May be None if the initial metadata will be later passed via the returned operator or if there will be no initial metadata passed at all. payload: An initial payload for the operation. completion: A Completion value indicating the end of transmission to the other side of the operation. protocol_options: A value specified by the provider of a Base interface implementation affording custom state and behavior. Returns: A pair of objects affording information about the operation and action continuing the operation. The first element of the returned pair is an OperationContext for the operation and the second element of the returned pair is an Operator to which operation values not passed in this call should later be passed. """ raise NotImplementedError() @abc.abstractmethod def operation_stats(self): """Reports the number of terminated operations broken down by outcome. Returns: A dictionary from Outcome.Kind value to an integer identifying the number of operations that terminated with that outcome kind. """ raise NotImplementedError() @abc.abstractmethod def add_idle_action(self, action): """Adds an action to be called when this End has no ongoing operations. Args: action: A callable that accepts no arguments. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/face/0000755000175000017500000000000012600663151022140 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/face/exceptions.py0000644000175000017500000000510612600663151024675 0ustar apollockapollock# 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. """Exceptions used in the Face layer of RPC Framework.""" import abc class NoSuchMethodError(Exception): """Raised by customer code to indicate an unrecognized RPC method name. Attributes: name: The unrecognized name. """ def __init__(self, name): """Constructor. Args: name: The unrecognized RPC method name. """ super(NoSuchMethodError, self).__init__() self.name = name class RpcError(Exception): """Common super type for all exceptions raised by the Face layer. Only RPC Framework should instantiate and raise these exceptions. """ __metaclass__ = abc.ABCMeta class CancellationError(RpcError): """Indicates that an RPC has been cancelled.""" class ExpirationError(RpcError): """Indicates that an RPC has expired ("timed out").""" class NetworkError(RpcError): """Indicates that some error occurred on the network.""" class ServicedError(RpcError): """Indicates that the Serviced failed in the course of an RPC.""" class ServicerError(RpcError): """Indicates that the Servicer failed in the course of servicing an RPC.""" grpc-0.11.1/src/python/grpcio/grpc/framework/face/_control.py0000644000175000017500000001553712600663151024344 0ustar apollockapollock# 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. """State and behavior for translating between sync and async control flow.""" import threading from grpc.framework.base import interfaces as base_interfaces from grpc.framework.face import exceptions from grpc.framework.face import interfaces from grpc.framework.foundation import abandonment from grpc.framework.foundation import stream INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Face) Internal Error! :-(' _OPERATION_OUTCOME_TO_RPC_ABORTION = { base_interfaces.Outcome.CANCELLED: interfaces.Abortion.CANCELLED, base_interfaces.Outcome.EXPIRED: interfaces.Abortion.EXPIRED, base_interfaces.Outcome.RECEPTION_FAILURE: interfaces.Abortion.NETWORK_FAILURE, base_interfaces.Outcome.TRANSMISSION_FAILURE: interfaces.Abortion.NETWORK_FAILURE, base_interfaces.Outcome.SERVICED_FAILURE: interfaces.Abortion.SERVICED_FAILURE, base_interfaces.Outcome.SERVICER_FAILURE: interfaces.Abortion.SERVICER_FAILURE, } def _as_operation_termination_callback(rpc_abortion_callback): def operation_termination_callback(operation_outcome): rpc_abortion = _OPERATION_OUTCOME_TO_RPC_ABORTION.get( operation_outcome, None) if rpc_abortion is not None: rpc_abortion_callback(rpc_abortion) return operation_termination_callback def _abortion_outcome_to_exception(abortion_outcome): if abortion_outcome == base_interfaces.Outcome.CANCELLED: return exceptions.CancellationError() elif abortion_outcome == base_interfaces.Outcome.EXPIRED: return exceptions.ExpirationError() elif abortion_outcome == base_interfaces.Outcome.SERVICER_FAILURE: return exceptions.ServicerError() elif abortion_outcome == base_interfaces.Outcome.SERVICED_FAILURE: return exceptions.ServicedError() else: return exceptions.NetworkError() class UnaryConsumer(stream.Consumer): """A stream.Consumer that should only ever be passed one value.""" def __init__(self, on_termination): self._on_termination = on_termination self._value = None def consume(self, value): self._value = value def terminate(self): self._on_termination(self._value) def consume_and_terminate(self, value): self._on_termination(value) class Rendezvous(stream.Consumer): """A rendez-vous with stream.Consumer and iterator interfaces.""" def __init__(self): self._condition = threading.Condition() self._values = [] self._values_completed = False self._abortion = None def consume(self, value): with self._condition: self._values.append(value) self._condition.notify() def terminate(self): with self._condition: self._values_completed = True self._condition.notify() def consume_and_terminate(self, value): with self._condition: self._values.append(value) self._values_completed = True self._condition.notify() def __iter__(self): return self def next(self): with self._condition: while ((self._abortion is None) and (not self._values) and (not self._values_completed)): self._condition.wait() if self._abortion is not None: raise _abortion_outcome_to_exception(self._abortion) elif self._values: return self._values.pop(0) elif self._values_completed: raise StopIteration() else: raise AssertionError('Unreachable code reached!') def set_outcome(self, outcome): with self._condition: if outcome is not base_interfaces.Outcome.COMPLETED: self._abortion = outcome self._condition.notify() class RpcContext(interfaces.RpcContext): """A wrapped base_interfaces.OperationContext.""" def __init__(self, operation_context): self._operation_context = operation_context def is_active(self): return self._operation_context.is_active() def time_remaining(self): return self._operation_context.time_remaining() def add_abortion_callback(self, abortion_callback): self._operation_context.add_termination_callback( _as_operation_termination_callback(abortion_callback)) def pipe_iterator_to_consumer(iterator, consumer, active, terminate): """Pipes values emitted from an iterator to a stream.Consumer. Args: iterator: An iterator from which values will be emitted. consumer: A stream.Consumer to which values will be passed. active: A no-argument callable that returns True if the work being done by this function is still valid and should not be abandoned and False if the work being done by this function should be abandoned. terminate: A boolean indicating whether or not this function should terminate the given consumer after passing to it all values emitted by the given iterator. Raises: abandonment.Abandoned: If this function quits early after seeing False returned by the active function passed to it. Exception: This function raises whatever exceptions are raised by iterating over the given iterator. """ for element in iterator: if not active(): raise abandonment.Abandoned() consumer.consume(element) if not active(): raise abandonment.Abandoned() if terminate: consumer.terminate() def abortion_outcome_to_exception(abortion_outcome): return _abortion_outcome_to_exception(abortion_outcome) def as_operation_termination_callback(rpc_abortion_callback): return _as_operation_termination_callback(rpc_abortion_callback) grpc-0.11.1/src/python/grpcio/grpc/framework/face/utilities.py0000644000175000017500000001534112600663151024531 0ustar apollockapollock# 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. """Utilities for RPC framework's face layer.""" import collections from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.face import interfaces from grpc.framework.foundation import stream class _MethodImplementation( interfaces.MethodImplementation, collections.namedtuple( '_MethodImplementation', ['cardinality', 'style', 'unary_unary_inline', 'unary_stream_inline', 'stream_unary_inline', 'stream_stream_inline', 'unary_unary_event', 'unary_stream_event', 'stream_unary_event', 'stream_stream_event',])): pass def unary_unary_inline(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-unary RPC method as a callable value that takes a request value and an interfaces.RpcContext object and returns a response value. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_UNARY, style.Service.INLINE, behavior, None, None, None, None, None, None, None) def unary_stream_inline(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-stream RPC method as a callable value that takes a request value and an interfaces.RpcContext object and returns an iterator of response values. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_STREAM, style.Service.INLINE, None, behavior, None, None, None, None, None, None) def stream_unary_inline(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-unary RPC method as a callable value that takes an iterator of request values and an interfaces.RpcContext object and returns a response value. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_UNARY, style.Service.INLINE, None, None, behavior, None, None, None, None, None) def stream_stream_inline(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-stream RPC method as a callable value that takes an iterator of request values and an interfaces.RpcContext object and returns an iterator of response values. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_STREAM, style.Service.INLINE, None, None, None, behavior, None, None, None, None) def unary_unary_event(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-unary RPC method as a callable value that takes a request value, a response callback to which to pass the response value of the RPC, and an interfaces.RpcContext. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_UNARY, style.Service.EVENT, None, None, None, None, behavior, None, None, None) def unary_stream_event(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a unary-stream RPC method as a callable value that takes a request value, a stream.Consumer to which to pass the the response values of the RPC, and an interfaces.RpcContext. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.UNARY_STREAM, style.Service.EVENT, None, None, None, None, None, behavior, None, None) def stream_unary_event(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-unary RPC method as a callable value that takes a response callback to which to pass the response value of the RPC and an interfaces.RpcContext and returns a stream.Consumer to which the request values of the RPC should be passed. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_UNARY, style.Service.EVENT, None, None, None, None, None, None, behavior, None) def stream_stream_event(behavior): """Creates an interfaces.MethodImplementation for the given behavior. Args: behavior: The implementation of a stream-stream RPC method as a callable value that takes a stream.Consumer to which to pass the response values of the RPC and an interfaces.RpcContext and returns a stream.Consumer to which the request values of the RPC should be passed. Returns: An interfaces.MethodImplementation derived from the given behavior. """ return _MethodImplementation( cardinality.Cardinality.STREAM_STREAM, style.Service.EVENT, None, None, None, None, None, None, None, behavior) grpc-0.11.1/src/python/grpcio/grpc/framework/face/interfaces.py0000644000175000017500000005556712600663151024657 0ustar apollockapollock# 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. """Interfaces for the face layer of RPC Framework.""" import abc import enum # cardinality, style, exceptions, abandonment, future, and stream are # referenced from specification in this module. from grpc.framework.common import cardinality # pylint: disable=unused-import from grpc.framework.common import style # pylint: disable=unused-import from grpc.framework.face import exceptions # pylint: disable=unused-import from grpc.framework.foundation import abandonment # pylint: disable=unused-import from grpc.framework.foundation import future # pylint: disable=unused-import from grpc.framework.foundation import stream # pylint: disable=unused-import @enum.unique class Abortion(enum.Enum): """Categories of RPC abortion.""" CANCELLED = 'cancelled' EXPIRED = 'expired' NETWORK_FAILURE = 'network failure' SERVICED_FAILURE = 'serviced failure' SERVICER_FAILURE = 'servicer failure' class CancellableIterator(object): """Implements the Iterator protocol and affords a cancel method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __iter__(self): """Returns the self object in accordance with the Iterator protocol.""" raise NotImplementedError() @abc.abstractmethod def next(self): """Returns a value or raises StopIteration per the Iterator protocol.""" raise NotImplementedError() @abc.abstractmethod def cancel(self): """Requests cancellation of whatever computation underlies this iterator.""" raise NotImplementedError() class RpcContext(object): """Provides RPC-related information and action.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): """Describes whether the RPC is active or has terminated.""" raise NotImplementedError() @abc.abstractmethod def time_remaining(self): """Describes the length of allowed time remaining for the RPC. Returns: A nonnegative float indicating the length of allowed time in seconds remaining for the RPC to complete before it is considered to have timed out. """ raise NotImplementedError() @abc.abstractmethod def add_abortion_callback(self, abortion_callback): """Registers a callback to be called if the RPC is aborted. Args: abortion_callback: A callable to be called and passed an Abortion value in the event of RPC abortion. """ raise NotImplementedError() class Call(object): """Invocation-side representation of an RPC. Attributes: context: An RpcContext affording information about the RPC. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def cancel(self): """Requests cancellation of the RPC.""" raise NotImplementedError() class UnaryUnaryMultiCallable(object): """Affords invoking a unary-unary RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout): """Synchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: The response value for the RPC. Raises: exceptions.RpcError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future(self, request, timeout): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A future.Future representing the RPC. In the event of RPC completion, the returned Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an exceptions.RpcError. """ raise NotImplementedError() @abc.abstractmethod def event(self, request, response_callback, abortion_callback, timeout): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. response_callback: A callback to be called to accept the restponse value of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A Call object for the RPC. """ raise NotImplementedError() class UnaryStreamMultiCallable(object): """Affords invoking a unary-stream RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request, timeout): """Synchronously invokes the underlying RPC. Args: request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A CancellableIterator that yields the response values of the RPC and affords RPC cancellation. Drawing response values from the returned CancellableIterator may raise exceptions.RpcError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def event(self, request, response_consumer, abortion_callback, timeout): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. response_consumer: A stream.Consumer to be called to accept the restponse values of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A Call object for the RPC. """ raise NotImplementedError() class StreamUnaryMultiCallable(object): """Affords invoking a stream-unary RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request_iterator, timeout): """Synchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: The response value for the RPC. Raises: exceptions.RpcError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future(self, request_iterator, timeout): """Asynchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A future.Future representing the RPC. In the event of RPC completion, the returned Future's result value will be the response value of the RPC. In the event of RPC abortion, the returned Future's exception value will be an exceptions.RpcError. """ raise NotImplementedError() @abc.abstractmethod def event(self, response_callback, abortion_callback, timeout): """Asynchronously invokes the underlying RPC. Args: request: The request value for the RPC. response_callback: A callback to be called to accept the restponse value of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A pair of a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() class StreamStreamMultiCallable(object): """Affords invoking a stream-stream RPC in any call style.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def __call__(self, request_iterator, timeout): """Synchronously invokes the underlying RPC. Args: request_iterator: An iterator that yields request values for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A CancellableIterator that yields the response values of the RPC and affords RPC cancellation. Drawing response values from the returned CancellableIterator may raise exceptions.RpcError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def event(self, response_consumer, abortion_callback, timeout): """Asynchronously invokes the underlying RPC. l Args: response_consumer: A stream.Consumer to be called to accept the restponse values of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A pair of a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() class MethodImplementation(object): """A sum type that describes an RPC method implementation. Attributes: cardinality: A cardinality.Cardinality value. style: A style.Service value. unary_unary_inline: The implementation of the RPC method as a callable value that takes a request value and an RpcContext object and returns a response value. Only non-None if cardinality is cardinality.Cardinality.UNARY_UNARY and style is style.Service.INLINE. unary_stream_inline: The implementation of the RPC method as a callable value that takes a request value and an RpcContext object and returns an iterator of response values. Only non-None if cardinality is cardinality.Cardinality.UNARY_STREAM and style is style.Service.INLINE. stream_unary_inline: The implementation of the RPC method as a callable value that takes an iterator of request values and an RpcContext object and returns a response value. Only non-None if cardinality is cardinality.Cardinality.STREAM_UNARY and style is style.Service.INLINE. stream_stream_inline: The implementation of the RPC method as a callable value that takes an iterator of request values and an RpcContext object and returns an iterator of response values. Only non-None if cardinality is cardinality.Cardinality.STREAM_STREAM and style is style.Service.INLINE. unary_unary_event: The implementation of the RPC method as a callable value that takes a request value, a response callback to which to pass the response value of the RPC, and an RpcContext. Only non-None if cardinality is cardinality.Cardinality.UNARY_UNARY and style is style.Service.EVENT. unary_stream_event: The implementation of the RPC method as a callable value that takes a request value, a stream.Consumer to which to pass the the response values of the RPC, and an RpcContext. Only non-None if cardinality is cardinality.Cardinality.UNARY_STREAM and style is style.Service.EVENT. stream_unary_event: The implementation of the RPC method as a callable value that takes a response callback to which to pass the response value of the RPC and an RpcContext and returns a stream.Consumer to which the request values of the RPC should be passed. Only non-None if cardinality is cardinality.Cardinality.STREAM_UNARY and style is style.Service.EVENT. stream_stream_event: The implementation of the RPC method as a callable value that takes a stream.Consumer to which to pass the response values of the RPC and an RpcContext and returns a stream.Consumer to which the request values of the RPC should be passed. Only non-None if cardinality is cardinality.Cardinality.STREAM_STREAM and style is style.Service.EVENT. """ __metaclass__ = abc.ABCMeta class MultiMethodImplementation(object): """A general type able to service many RPC methods.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, name, response_consumer, context): """Services an RPC. Args: name: The RPC method name. response_consumer: A stream.Consumer to be called to accept the response values of the RPC. context: An RpcContext object. Returns: A stream.Consumer with which to accept the request values of the RPC. The consumer returned from this method may or may not be invoked to completion: in the case of RPC abortion, RPC Framework will simply stop passing values to this object. Implementations must not assume that this object will be called to completion of the request stream or even called at all. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. exceptions.NoSuchMethodError: If this MultiMethod does not recognize the given RPC method name and is not able to service the RPC. """ raise NotImplementedError() class GenericStub(object): """Affords RPC methods to callers.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def blocking_value_in_value_out(self, name, request, timeout): """Invokes a unary-request-unary-response RPC method. This method blocks until either returning the response value of the RPC (in the event of RPC completion) or raising an exception (in the event of RPC abortion). Args: name: The RPC method name. request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: The response value for the RPC. Raises: exceptions.RpcError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future_value_in_value_out(self, name, request, timeout): """Invokes a unary-request-unary-response RPC method. Args: name: The RPC method name. request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A future.Future representing the RPC. In the event of RPC completion, the returned Future will return an outcome indicating that the RPC returned the response value of the RPC. In the event of RPC abortion, the returned Future will return an outcome indicating that the RPC raised an exceptions.RpcError. """ raise NotImplementedError() @abc.abstractmethod def inline_value_in_stream_out(self, name, request, timeout): """Invokes a unary-request-stream-response RPC method. Args: name: The RPC method name. request: The request value for the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A CancellableIterator that yields the response values of the RPC and affords RPC cancellation. Drawing response values from the returned CancellableIterator may raise exceptions.RpcError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def blocking_stream_in_value_out(self, name, request_iterator, timeout): """Invokes a stream-request-unary-response RPC method. This method blocks until either returning the response value of the RPC (in the event of RPC completion) or raising an exception (in the event of RPC abortion). Args: name: The RPC method name. request_iterator: An iterator that yields the request values of the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: The response value for the RPC. Raises: exceptions.RpcError: Indicating that the RPC was aborted. """ raise NotImplementedError() @abc.abstractmethod def future_stream_in_value_out(self, name, request_iterator, timeout): """Invokes a stream-request-unary-response RPC method. Args: name: The RPC method name. request_iterator: An iterator that yields the request values of the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A future.Future representing the RPC. In the event of RPC completion, the returned Future will return an outcome indicating that the RPC returned the response value of the RPC. In the event of RPC abortion, the returned Future will return an outcome indicating that the RPC raised an exceptions.RpcError. """ raise NotImplementedError() @abc.abstractmethod def inline_stream_in_stream_out(self, name, request_iterator, timeout): """Invokes a stream-request-stream-response RPC method. Args: name: The RPC method name. request_iterator: An iterator that yields the request values of the RPC. timeout: A duration of time in seconds to allow for the RPC. Returns: A CancellableIterator that yields the response values of the RPC and affords RPC cancellation. Drawing response values from the returned CancellableIterator may raise exceptions.RpcError indicating abortion of the RPC. """ raise NotImplementedError() @abc.abstractmethod def event_value_in_value_out( self, name, request, response_callback, abortion_callback, timeout): """Event-driven invocation of a unary-request-unary-response RPC method. Args: name: The RPC method name. request: The request value for the RPC. response_callback: A callback to be called to accept the response value of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A Call object for the RPC. """ raise NotImplementedError() @abc.abstractmethod def event_value_in_stream_out( self, name, request, response_consumer, abortion_callback, timeout): """Event-driven invocation of a unary-request-stream-response RPC method. Args: name: The RPC method name. request: The request value for the RPC. response_consumer: A stream.Consumer to be called to accept the response values of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A Call object for the RPC. """ raise NotImplementedError() @abc.abstractmethod def event_stream_in_value_out( self, name, response_callback, abortion_callback, timeout): """Event-driven invocation of a unary-request-unary-response RPC method. Args: name: The RPC method name. response_callback: A callback to be called to accept the response value of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A pair of a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() @abc.abstractmethod def event_stream_in_stream_out( self, name, response_consumer, abortion_callback, timeout): """Event-driven invocation of a unary-request-stream-response RPC method. Args: name: The RPC method name. response_consumer: A stream.Consumer to be called to accept the response values of the RPC. abortion_callback: A callback to be called and passed an Abortion value in the event of RPC abortion. timeout: A duration of time in seconds to allow for the RPC. Returns: A pair of a Call object for the RPC and a stream.Consumer to which the request values of the RPC should be passed. """ raise NotImplementedError() @abc.abstractmethod def unary_unary_multi_callable(self, name): """Creates a UnaryUnaryMultiCallable for a unary-unary RPC method. Args: name: The RPC method name. Returns: A UnaryUnaryMultiCallable value for the named unary-unary RPC method. """ raise NotImplementedError() @abc.abstractmethod def unary_stream_multi_callable(self, name): """Creates a UnaryStreamMultiCallable for a unary-stream RPC method. Args: name: The RPC method name. Returns: A UnaryStreamMultiCallable value for the name unary-stream RPC method. """ raise NotImplementedError() @abc.abstractmethod def stream_unary_multi_callable(self, name): """Creates a StreamUnaryMultiCallable for a stream-unary RPC method. Args: name: The RPC method name. Returns: A StreamUnaryMultiCallable value for the named stream-unary RPC method. """ raise NotImplementedError() @abc.abstractmethod def stream_stream_multi_callable(self, name): """Creates a StreamStreamMultiCallable for a stream-stream RPC method. Args: name: The RPC method name. Returns: A StreamStreamMultiCallable value for the named stream-stream RPC method. """ raise NotImplementedError() class DynamicStub(object): """A stub with RPC-method-bound multi-callable attributes. Instances of this type responsd to attribute access as follows: if the requested attribute is the name of a unary-unary RPC method, the value of the attribute will be a UnaryUnaryMultiCallable with which to invoke the RPC method; if the requested attribute is the name of a unary-stream RPC method, the value of the attribute will be a UnaryStreamMultiCallable with which to invoke the RPC method; if the requested attribute is the name of a stream-unary RPC method, the value of the attribute will be a StreamUnaryMultiCallable with which to invoke the RPC method; and if the requested attribute is the name of a stream-stream RPC method, the value of the attribute will be a StreamStreamMultiCallable with which to invoke the RPC method. """ __metaclass__ = abc.ABCMeta grpc-0.11.1/src/python/grpcio/grpc/framework/face/implementations.py0000644000175000017500000003143612600663151025731 0ustar apollockapollock# 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. """Entry points into the Face layer of RPC Framework.""" from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.base import exceptions as _base_exceptions from grpc.framework.base import interfaces as base_interfaces from grpc.framework.face import _calls from grpc.framework.face import _service from grpc.framework.face import exceptions from grpc.framework.face import interfaces class _BaseServicer(base_interfaces.Servicer): def __init__(self, methods, multi_method): self._methods = methods self._multi_method = multi_method def service(self, name, context, output_consumer): method = self._methods.get(name, None) if method is not None: return method(output_consumer, context) elif self._multi_method is not None: try: return self._multi_method.service(name, output_consumer, context) except exceptions.NoSuchMethodError: raise _base_exceptions.NoSuchMethodError() else: raise _base_exceptions.NoSuchMethodError() class _UnaryUnaryMultiCallable(interfaces.UnaryUnaryMultiCallable): def __init__(self, front, name): self._front = front self._name = name def __call__(self, request, timeout): return _calls.blocking_value_in_value_out( self._front, self._name, request, timeout, 'unused trace ID') def future(self, request, timeout): return _calls.future_value_in_value_out( self._front, self._name, request, timeout, 'unused trace ID') def event(self, request, response_callback, abortion_callback, timeout): return _calls.event_value_in_value_out( self._front, self._name, request, response_callback, abortion_callback, timeout, 'unused trace ID') class _UnaryStreamMultiCallable(interfaces.UnaryStreamMultiCallable): def __init__(self, front, name): self._front = front self._name = name def __call__(self, request, timeout): return _calls.inline_value_in_stream_out( self._front, self._name, request, timeout, 'unused trace ID') def event(self, request, response_consumer, abortion_callback, timeout): return _calls.event_value_in_stream_out( self._front, self._name, request, response_consumer, abortion_callback, timeout, 'unused trace ID') class _StreamUnaryMultiCallable(interfaces.StreamUnaryMultiCallable): def __init__(self, front, name, pool): self._front = front self._name = name self._pool = pool def __call__(self, request_iterator, timeout): return _calls.blocking_stream_in_value_out( self._front, self._name, request_iterator, timeout, 'unused trace ID') def future(self, request_iterator, timeout): return _calls.future_stream_in_value_out( self._front, self._name, request_iterator, timeout, 'unused trace ID', self._pool) def event(self, response_callback, abortion_callback, timeout): return _calls.event_stream_in_value_out( self._front, self._name, response_callback, abortion_callback, timeout, 'unused trace ID') class _StreamStreamMultiCallable(interfaces.StreamStreamMultiCallable): def __init__(self, front, name, pool): self._front = front self._name = name self._pool = pool def __call__(self, request_iterator, timeout): return _calls.inline_stream_in_stream_out( self._front, self._name, request_iterator, timeout, 'unused trace ID', self._pool) def event(self, response_consumer, abortion_callback, timeout): return _calls.event_stream_in_stream_out( self._front, self._name, response_consumer, abortion_callback, timeout, 'unused trace ID') class _GenericStub(interfaces.GenericStub): """An interfaces.GenericStub implementation.""" def __init__(self, front, pool): self._front = front self._pool = pool def blocking_value_in_value_out(self, name, request, timeout): return _calls.blocking_value_in_value_out( self._front, name, request, timeout, 'unused trace ID') def future_value_in_value_out(self, name, request, timeout): return _calls.future_value_in_value_out( self._front, name, request, timeout, 'unused trace ID') def inline_value_in_stream_out(self, name, request, timeout): return _calls.inline_value_in_stream_out( self._front, name, request, timeout, 'unused trace ID') def blocking_stream_in_value_out(self, name, request_iterator, timeout): return _calls.blocking_stream_in_value_out( self._front, name, request_iterator, timeout, 'unused trace ID') def future_stream_in_value_out(self, name, request_iterator, timeout): return _calls.future_stream_in_value_out( self._front, name, request_iterator, timeout, 'unused trace ID', self._pool) def inline_stream_in_stream_out(self, name, request_iterator, timeout): return _calls.inline_stream_in_stream_out( self._front, name, request_iterator, timeout, 'unused trace ID', self._pool) def event_value_in_value_out( self, name, request, response_callback, abortion_callback, timeout): return _calls.event_value_in_value_out( self._front, name, request, response_callback, abortion_callback, timeout, 'unused trace ID') def event_value_in_stream_out( self, name, request, response_consumer, abortion_callback, timeout): return _calls.event_value_in_stream_out( self._front, name, request, response_consumer, abortion_callback, timeout, 'unused trace ID') def event_stream_in_value_out( self, name, response_callback, abortion_callback, timeout): return _calls.event_stream_in_value_out( self._front, name, response_callback, abortion_callback, timeout, 'unused trace ID') def event_stream_in_stream_out( self, name, response_consumer, abortion_callback, timeout): return _calls.event_stream_in_stream_out( self._front, name, response_consumer, abortion_callback, timeout, 'unused trace ID') def unary_unary_multi_callable(self, name): return _UnaryUnaryMultiCallable(self._front, name) def unary_stream_multi_callable(self, name): return _UnaryStreamMultiCallable(self._front, name) def stream_unary_multi_callable(self, name): return _StreamUnaryMultiCallable(self._front, name, self._pool) def stream_stream_multi_callable(self, name): return _StreamStreamMultiCallable(self._front, name, self._pool) class _DynamicStub(interfaces.DynamicStub): """An interfaces.DynamicStub implementation.""" def __init__(self, cardinalities, front, pool): self._cardinalities = cardinalities self._front = front self._pool = pool def __getattr__(self, attr): method_cardinality = self._cardinalities.get(attr) if method_cardinality is cardinality.Cardinality.UNARY_UNARY: return _UnaryUnaryMultiCallable(self._front, attr) elif method_cardinality is cardinality.Cardinality.UNARY_STREAM: return _UnaryStreamMultiCallable(self._front, attr) elif method_cardinality is cardinality.Cardinality.STREAM_UNARY: return _StreamUnaryMultiCallable(self._front, attr, self._pool) elif method_cardinality is cardinality.Cardinality.STREAM_STREAM: return _StreamStreamMultiCallable(self._front, attr, self._pool) else: raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr) def _adapt_method_implementations(method_implementations, pool): adapted_implementations = {} for name, method_implementation in method_implementations.iteritems(): if method_implementation.style is style.Service.INLINE: if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: adapted_implementations[name] = _service.adapt_inline_value_in_value_out( method_implementation.unary_unary_inline) elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM: adapted_implementations[name] = _service.adapt_inline_value_in_stream_out( method_implementation.unary_stream_inline) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY: adapted_implementations[name] = _service.adapt_inline_stream_in_value_out( method_implementation.stream_unary_inline, pool) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM: adapted_implementations[name] = _service.adapt_inline_stream_in_stream_out( method_implementation.stream_stream_inline, pool) elif method_implementation.style is style.Service.EVENT: if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: adapted_implementations[name] = _service.adapt_event_value_in_value_out( method_implementation.unary_unary_event) elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM: adapted_implementations[name] = _service.adapt_event_value_in_stream_out( method_implementation.unary_stream_event) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY: adapted_implementations[name] = _service.adapt_event_stream_in_value_out( method_implementation.stream_unary_event) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM: adapted_implementations[name] = _service.adapt_event_stream_in_stream_out( method_implementation.stream_stream_event) return adapted_implementations def servicer(pool, method_implementations, multi_method_implementation): """Creates a base_interfaces.Servicer. It is guaranteed that any passed interfaces.MultiMethodImplementation will only be called to service an RPC if there is no interfaces.MethodImplementation for the RPC method in the passed method_implementations dictionary. Args: pool: A thread pool. method_implementations: A dictionary from RPC method name to interfaces.MethodImplementation object to be used to service the named RPC method. multi_method_implementation: An interfaces.MultiMethodImplementation to be used to service any RPCs not serviced by the interfaces.MethodImplementations given in the method_implementations dictionary, or None. Returns: A base_interfaces.Servicer that services RPCs via the given implementations. """ adapted_implementations = _adapt_method_implementations( method_implementations, pool) return _BaseServicer(adapted_implementations, multi_method_implementation) def generic_stub(front, pool): """Creates an interfaces.GenericStub. Args: front: A base_interfaces.Front. pool: A futures.ThreadPoolExecutor. Returns: An interfaces.GenericStub that performs RPCs via the given base_interfaces.Front. """ return _GenericStub(front, pool) def dynamic_stub(cardinalities, front, pool, prefix): """Creates an interfaces.DynamicStub. Args: cardinalities: A dict from RPC method name to cardinality.Cardinality value identifying the cardinality of every RPC method to be supported by the created interfaces.DynamicStub. front: A base_interfaces.Front. pool: A futures.ThreadPoolExecutor. prefix: A string to prepend when mapping requested attribute name to RPC method name during attribute access on the created interfaces.DynamicStub. Returns: An interfaces.DynamicStub that performs RPCs via the given base_interfaces.Front. """ return _DynamicStub(cardinalities, front, pool) grpc-0.11.1/src/python/grpcio/grpc/framework/face/_calls.py0000644000175000017500000003547312600663151023763 0ustar apollockapollock# 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. """Utility functions for invoking RPCs.""" import sys import threading from grpc.framework.base import interfaces as base_interfaces from grpc.framework.base import util as base_util from grpc.framework.face import _control from grpc.framework.face import interfaces from grpc.framework.foundation import callable_util from grpc.framework.foundation import future _ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!' _DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!' class _RendezvousServicedIngestor(base_interfaces.ServicedIngestor): def __init__(self, rendezvous): self._rendezvous = rendezvous def consumer(self, operation_context): return self._rendezvous class _EventServicedIngestor(base_interfaces.ServicedIngestor): def __init__(self, result_consumer, abortion_callback): self._result_consumer = result_consumer self._abortion_callback = abortion_callback def consumer(self, operation_context): operation_context.add_termination_callback( _control.as_operation_termination_callback(self._abortion_callback)) return self._result_consumer def _rendezvous_subscription(rendezvous): return base_util.full_serviced_subscription( _RendezvousServicedIngestor(rendezvous)) def _unary_event_subscription(completion_callback, abortion_callback): return base_util.full_serviced_subscription( _EventServicedIngestor( _control.UnaryConsumer(completion_callback), abortion_callback)) def _stream_event_subscription(result_consumer, abortion_callback): return base_util.full_serviced_subscription( _EventServicedIngestor(result_consumer, abortion_callback)) # NOTE(nathaniel): This class has some extremely special semantics around # cancellation that allow it to be used by both "blocking" APIs and "futures" # APIs. # # Since futures.Future defines its own exception for cancellation, we want these # objects, when returned by methods of a returning-Futures-from-other-methods # object, to raise the same exception for cancellation. But that's weird in a # blocking API - why should this object, also returned by methods of blocking # APIs, raise exceptions from the "future" module? Should we do something like # have this class be parameterized by the type of exception that it raises in # cancellation circumstances? # # We don't have to take such a dramatic step: since blocking APIs define no # cancellation semantics whatsoever, there is no supported way for # blocking-API-users of these objects to cancel RPCs, and thus no supported way # for them to see an exception the type of which would be weird to them. # # Bonus: in both blocking and futures APIs, this object still properly raises # exceptions.CancellationError for any *server-side cancellation* of an RPC. class _OperationCancellableIterator(interfaces.CancellableIterator): """An interfaces.CancellableIterator for response-streaming operations.""" def __init__(self, rendezvous, operation): self._lock = threading.Lock() self._rendezvous = rendezvous self._operation = operation self._cancelled = False def __iter__(self): return self def next(self): with self._lock: if self._cancelled: raise future.CancelledError() return next(self._rendezvous) def cancel(self): with self._lock: self._cancelled = True self._operation.cancel() self._rendezvous.set_outcome(base_interfaces.Outcome.CANCELLED) class _OperationFuture(future.Future): """A future.Future interface to an operation.""" def __init__(self, rendezvous, operation): self._condition = threading.Condition() self._rendezvous = rendezvous self._operation = operation self._cancelled = False self._computed = False self._payload = None self._exception = None self._traceback = None self._callbacks = [] def cancel(self): """See future.Future.cancel for specification.""" with self._condition: if not self._cancelled and not self._computed: self._operation.cancel() self._cancelled = True self._condition.notify_all() return False def cancelled(self): """See future.Future.cancelled for specification.""" with self._condition: return self._cancelled def running(self): """See future.Future.running for specification.""" with self._condition: return not self._cancelled and not self._computed def done(self): """See future.Future.done for specification.""" with self._condition: return self._cancelled or self._computed def result(self, timeout=None): """See future.Future.result for specification.""" with self._condition: if self._cancelled: raise future.CancelledError() if self._computed: if self._payload is None: raise self._exception # pylint: disable=raising-bad-type else: return self._payload condition = threading.Condition() def notify_condition(unused_future): with condition: condition.notify() self._callbacks.append(notify_condition) with condition: condition.wait(timeout=timeout) with self._condition: if self._cancelled: raise future.CancelledError() elif self._computed: if self._payload is None: raise self._exception # pylint: disable=raising-bad-type else: return self._payload else: raise future.TimeoutError() def exception(self, timeout=None): """See future.Future.exception for specification.""" with self._condition: if self._cancelled: raise future.CancelledError() if self._computed: return self._exception condition = threading.Condition() def notify_condition(unused_future): with condition: condition.notify() self._callbacks.append(notify_condition) with condition: condition.wait(timeout=timeout) with self._condition: if self._cancelled: raise future.CancelledError() elif self._computed: return self._exception else: raise future.TimeoutError() def traceback(self, timeout=None): """See future.Future.traceback for specification.""" with self._condition: if self._cancelled: raise future.CancelledError() if self._computed: return self._traceback condition = threading.Condition() def notify_condition(unused_future): with condition: condition.notify() self._callbacks.append(notify_condition) with condition: condition.wait(timeout=timeout) with self._condition: if self._cancelled: raise future.CancelledError() elif self._computed: return self._traceback else: raise future.TimeoutError() def add_done_callback(self, fn): """See future.Future.add_done_callback for specification.""" with self._condition: if self._callbacks is not None: self._callbacks.append(fn) return callable_util.call_logging_exceptions(fn, _DONE_CALLBACK_LOG_MESSAGE, self) def on_operation_termination(self, operation_outcome): """Indicates to this object that the operation has terminated. Args: operation_outcome: A base_interfaces.Outcome value indicating the outcome of the operation. """ with self._condition: cancelled = self._cancelled if cancelled: callbacks = list(self._callbacks) self._callbacks = None else: rendezvous = self._rendezvous if not cancelled: payload = None exception = None traceback = None if operation_outcome == base_interfaces.Outcome.COMPLETED: try: payload = next(rendezvous) except Exception as e: # pylint: disable=broad-except exception = e traceback = sys.exc_info()[2] else: try: # We raise and then immediately catch in order to create a traceback. raise _control.abortion_outcome_to_exception(operation_outcome) except Exception as e: # pylint: disable=broad-except exception = e traceback = sys.exc_info()[2] with self._condition: if not self._cancelled: self._computed = True self._payload = payload self._exception = exception self._traceback = traceback callbacks = list(self._callbacks) self._callbacks = None for callback in callbacks: callable_util.call_logging_exceptions( callback, _DONE_CALLBACK_LOG_MESSAGE, self) class _Call(interfaces.Call): def __init__(self, operation): self._operation = operation self.context = _control.RpcContext(operation.context) def cancel(self): self._operation.cancel() def blocking_value_in_value_out(front, name, payload, timeout, trace_id): """Services in a blocking fashion a value-in value-out servicer method.""" rendezvous = _control.Rendezvous() subscription = _rendezvous_subscription(rendezvous) operation = front.operate( name, payload, True, timeout, subscription, trace_id) operation.context.add_termination_callback(rendezvous.set_outcome) return next(rendezvous) def future_value_in_value_out(front, name, payload, timeout, trace_id): """Services a value-in value-out servicer method by returning a Future.""" rendezvous = _control.Rendezvous() subscription = _rendezvous_subscription(rendezvous) operation = front.operate( name, payload, True, timeout, subscription, trace_id) operation.context.add_termination_callback(rendezvous.set_outcome) operation_future = _OperationFuture(rendezvous, operation) operation.context.add_termination_callback( operation_future.on_operation_termination) return operation_future def inline_value_in_stream_out(front, name, payload, timeout, trace_id): """Services a value-in stream-out servicer method.""" rendezvous = _control.Rendezvous() subscription = _rendezvous_subscription(rendezvous) operation = front.operate( name, payload, True, timeout, subscription, trace_id) operation.context.add_termination_callback(rendezvous.set_outcome) return _OperationCancellableIterator(rendezvous, operation) def blocking_stream_in_value_out( front, name, payload_iterator, timeout, trace_id): """Services in a blocking fashion a stream-in value-out servicer method.""" rendezvous = _control.Rendezvous() subscription = _rendezvous_subscription(rendezvous) operation = front.operate(name, None, False, timeout, subscription, trace_id) operation.context.add_termination_callback(rendezvous.set_outcome) for payload in payload_iterator: operation.consumer.consume(payload) operation.consumer.terminate() return next(rendezvous) def future_stream_in_value_out( front, name, payload_iterator, timeout, trace_id, pool): """Services a stream-in value-out servicer method by returning a Future.""" rendezvous = _control.Rendezvous() subscription = _rendezvous_subscription(rendezvous) operation = front.operate(name, None, False, timeout, subscription, trace_id) operation.context.add_termination_callback(rendezvous.set_outcome) pool.submit( callable_util.with_exceptions_logged( _control.pipe_iterator_to_consumer, _ITERATOR_EXCEPTION_LOG_MESSAGE), payload_iterator, operation.consumer, lambda: True, True) operation_future = _OperationFuture(rendezvous, operation) operation.context.add_termination_callback( operation_future.on_operation_termination) return operation_future def inline_stream_in_stream_out( front, name, payload_iterator, timeout, trace_id, pool): """Services a stream-in stream-out servicer method.""" rendezvous = _control.Rendezvous() subscription = _rendezvous_subscription(rendezvous) operation = front.operate(name, None, False, timeout, subscription, trace_id) operation.context.add_termination_callback(rendezvous.set_outcome) pool.submit( callable_util.with_exceptions_logged( _control.pipe_iterator_to_consumer, _ITERATOR_EXCEPTION_LOG_MESSAGE), payload_iterator, operation.consumer, lambda: True, True) return _OperationCancellableIterator(rendezvous, operation) def event_value_in_value_out( front, name, payload, completion_callback, abortion_callback, timeout, trace_id): subscription = _unary_event_subscription( completion_callback, abortion_callback) operation = front.operate( name, payload, True, timeout, subscription, trace_id) return _Call(operation) def event_value_in_stream_out( front, name, payload, result_payload_consumer, abortion_callback, timeout, trace_id): subscription = _stream_event_subscription( result_payload_consumer, abortion_callback) operation = front.operate( name, payload, True, timeout, subscription, trace_id) return _Call(operation) def event_stream_in_value_out( front, name, completion_callback, abortion_callback, timeout, trace_id): subscription = _unary_event_subscription( completion_callback, abortion_callback) operation = front.operate(name, None, False, timeout, subscription, trace_id) return _Call(operation), operation.consumer def event_stream_in_stream_out( front, name, result_payload_consumer, abortion_callback, timeout, trace_id): subscription = _stream_event_subscription( result_payload_consumer, abortion_callback) operation = front.operate(name, None, False, timeout, subscription, trace_id) return _Call(operation), operation.consumer grpc-0.11.1/src/python/grpcio/grpc/framework/face/__init__.py0000644000175000017500000000277212600663151024261 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/face/demonstration.py0000644000175000017500000001115612600663151025404 0ustar apollockapollock# 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. """Demonstration-suitable implementation of the face layer of RPC Framework.""" from grpc.framework.base import util as _base_util from grpc.framework.base import implementations as _base_implementations from grpc.framework.face import implementations from grpc.framework.foundation import logging_pool _POOL_SIZE_LIMIT = 5 _MAXIMUM_TIMEOUT = 90 class LinkedPair(object): """A Server and Stub that are linked to one another. Attributes: server: A Server. stub: A Stub. """ def shut_down(self): """Shuts down this object and releases its resources.""" raise NotImplementedError() class _LinkedPair(LinkedPair): def __init__(self, server, stub, front, back, pools): self.server = server self.stub = stub self._front = front self._back = back self._pools = pools def shut_down(self): _base_util.wait_for_idle(self._front) _base_util.wait_for_idle(self._back) for pool in self._pools: pool.shutdown(wait=True) def server_and_stub( default_timeout, inline_value_in_value_out_methods=None, inline_value_in_stream_out_methods=None, inline_stream_in_value_out_methods=None, inline_stream_in_stream_out_methods=None, event_value_in_value_out_methods=None, event_value_in_stream_out_methods=None, event_stream_in_value_out_methods=None, event_stream_in_stream_out_methods=None, multi_method=None): """Creates a Server and Stub linked together for use.""" front_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT) front_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT) front_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT) back_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT) back_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT) back_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT) stub_pool = logging_pool.pool(_POOL_SIZE_LIMIT) pools = ( front_work_pool, front_transmission_pool, front_utility_pool, back_work_pool, back_transmission_pool, back_utility_pool, stub_pool) servicer = implementations.servicer( back_work_pool, inline_value_in_value_out_methods=inline_value_in_value_out_methods, inline_value_in_stream_out_methods=inline_value_in_stream_out_methods, inline_stream_in_value_out_methods=inline_stream_in_value_out_methods, inline_stream_in_stream_out_methods=inline_stream_in_stream_out_methods, event_value_in_value_out_methods=event_value_in_value_out_methods, event_value_in_stream_out_methods=event_value_in_stream_out_methods, event_stream_in_value_out_methods=event_stream_in_value_out_methods, event_stream_in_stream_out_methods=event_stream_in_stream_out_methods, multi_method=multi_method) front = _base_implementations.front_link( front_work_pool, front_transmission_pool, front_utility_pool) back = _base_implementations.back_link( servicer, back_work_pool, back_transmission_pool, back_utility_pool, default_timeout, _MAXIMUM_TIMEOUT) front.join_rear_link(back) back.join_fore_link(front) stub = implementations.stub(front, stub_pool) return _LinkedPair(implementations.server(), stub, front, back, pools) grpc-0.11.1/src/python/grpcio/grpc/framework/face/_service.py0000644000175000017500000001602312600663151024313 0ustar apollockapollock# 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. """Behaviors for servicing RPCs.""" # base_interfaces and interfaces are referenced from specification in this # module. from grpc.framework.base import interfaces as base_interfaces # pylint: disable=unused-import from grpc.framework.face import _control from grpc.framework.face import exceptions from grpc.framework.face import interfaces # pylint: disable=unused-import from grpc.framework.foundation import abandonment from grpc.framework.foundation import callable_util from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util class _ValueInStreamOutConsumer(stream.Consumer): """A stream.Consumer that maps inputs one-to-many onto outputs.""" def __init__(self, behavior, context, downstream): """Constructor. Args: behavior: A callable that takes a single value and an interfaces.RpcContext and returns a generator of arbitrarily many values. context: An interfaces.RpcContext. downstream: A stream.Consumer to which to pass the values generated by the given behavior. """ self._behavior = behavior self._context = context self._downstream = downstream def consume(self, value): _control.pipe_iterator_to_consumer( self._behavior(value, self._context), self._downstream, self._context.is_active, False) def terminate(self): self._downstream.terminate() def consume_and_terminate(self, value): _control.pipe_iterator_to_consumer( self._behavior(value, self._context), self._downstream, self._context.is_active, True) def _pool_wrap(behavior, operation_context): """Wraps an operation-related behavior so that it may be called in a pool. Args: behavior: A callable related to carrying out an operation. operation_context: A base_interfaces.OperationContext for the operation. Returns: A callable that when called carries out the behavior of the given callable and handles whatever exceptions it raises appropriately. """ def translation(*args): try: behavior(*args) except ( abandonment.Abandoned, exceptions.ExpirationError, exceptions.CancellationError, exceptions.ServicedError, exceptions.NetworkError) as e: if operation_context.is_active(): operation_context.fail(e) except Exception as e: operation_context.fail(e) return callable_util.with_exceptions_logged( translation, _control.INTERNAL_ERROR_LOG_MESSAGE) def adapt_inline_value_in_value_out(method): def adaptation(response_consumer, operation_context): rpc_context = _control.RpcContext(operation_context) return stream_util.TransformingConsumer( lambda request: method(request, rpc_context), response_consumer) return adaptation def adapt_inline_value_in_stream_out(method): def adaptation(response_consumer, operation_context): rpc_context = _control.RpcContext(operation_context) return _ValueInStreamOutConsumer(method, rpc_context, response_consumer) return adaptation def adapt_inline_stream_in_value_out(method, pool): def adaptation(response_consumer, operation_context): rendezvous = _control.Rendezvous() operation_context.add_termination_callback(rendezvous.set_outcome) def in_pool_thread(): response_consumer.consume_and_terminate( method(rendezvous, _control.RpcContext(operation_context))) pool.submit(_pool_wrap(in_pool_thread, operation_context)) return rendezvous return adaptation def adapt_inline_stream_in_stream_out(method, pool): """Adapts an interfaces.InlineStreamInStreamOutMethod for use with Consumers. RPCs may be serviced by calling the return value of this function, passing request values to the stream.Consumer returned from that call, and receiving response values from the stream.Consumer passed to that call. Args: method: An interfaces.InlineStreamInStreamOutMethod. pool: A thread pool. Returns: A callable that takes a stream.Consumer and a base_interfaces.OperationContext and returns a stream.Consumer. """ def adaptation(response_consumer, operation_context): rendezvous = _control.Rendezvous() operation_context.add_termination_callback(rendezvous.set_outcome) def in_pool_thread(): _control.pipe_iterator_to_consumer( method(rendezvous, _control.RpcContext(operation_context)), response_consumer, operation_context.is_active, True) pool.submit(_pool_wrap(in_pool_thread, operation_context)) return rendezvous return adaptation def adapt_event_value_in_value_out(method): def adaptation(response_consumer, operation_context): def on_payload(payload): method( payload, response_consumer.consume_and_terminate, _control.RpcContext(operation_context)) return _control.UnaryConsumer(on_payload) return adaptation def adapt_event_value_in_stream_out(method): def adaptation(response_consumer, operation_context): def on_payload(payload): method( payload, response_consumer, _control.RpcContext(operation_context)) return _control.UnaryConsumer(on_payload) return adaptation def adapt_event_stream_in_value_out(method): def adaptation(response_consumer, operation_context): rpc_context = _control.RpcContext(operation_context) return method(response_consumer.consume_and_terminate, rpc_context) return adaptation def adapt_event_stream_in_stream_out(method): def adaptation(response_consumer, operation_context): return method(response_consumer, _control.RpcContext(operation_context)) return adaptation grpc-0.11.1/src/python/grpcio/grpc/framework/common/0000755000175000017500000000000012600663151022532 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/common/style.py0000644000175000017500000000335212600663151024247 0ustar apollockapollock# 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. """Defines an enum for classifying RPC methods by control flow semantics.""" import enum @enum.unique class Service(enum.Enum): """Describes the control flow style of RPC method implementation.""" INLINE = 'inline' EVENT = 'event' grpc-0.11.1/src/python/grpcio/grpc/framework/common/cardinality.py0000644000175000017500000000361212600663151025411 0ustar apollockapollock# 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. """Defines an enum for classifying RPC methods by streaming semantics.""" import enum @enum.unique class Cardinality(enum.Enum): """Describes the streaming semantics of an RPC method.""" UNARY_UNARY = 'request-unary/response-unary' UNARY_STREAM = 'request-unary/response-streaming' STREAM_UNARY = 'request-streaming/response-unary' STREAM_STREAM = 'request-streaming/response-streaming' grpc-0.11.1/src/python/grpcio/grpc/framework/common/__init__.py0000644000175000017500000000277212600663151024653 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/__init__.py0000644000175000017500000000277212600663151023363 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/0000755000175000017500000000000012600663151023410 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/foundation/logging_pool.py0000644000175000017500000000575412600663151026454 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A thread pool that logs exceptions raised by tasks executed within it.""" import functools import logging from concurrent import futures def _wrap(behavior): """Wraps an arbitrary callable behavior in exception-logging.""" @functools.wraps(behavior) def _wrapping(*args, **kwargs): try: return behavior(*args, **kwargs) except Exception as e: logging.exception('Unexpected exception from task run in logging pool!') raise return _wrapping class _LoggingPool(object): """An exception-logging futures.ThreadPoolExecutor-compatible thread pool.""" def __init__(self, backing_pool): self._backing_pool = backing_pool def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._backing_pool.shutdown(wait=True) def submit(self, fn, *args, **kwargs): return self._backing_pool.submit(_wrap(fn), *args, **kwargs) def map(self, func, *iterables, **kwargs): return self._backing_pool.map( _wrap(func), *iterables, timeout=kwargs.get('timeout', None)) def shutdown(self, wait=True): self._backing_pool.shutdown(wait=wait) def pool(max_workers): """Creates a thread pool that logs exceptions raised by the tasks within it. Args: max_workers: The maximum number of worker threads to allow the pool. Returns: A futures.ThreadPoolExecutor-compatible thread pool that logs exceptions raised by the tasks executed within it. """ return _LoggingPool(futures.ThreadPoolExecutor(max_workers)) grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/relay.py0000644000175000017500000001302312600663151025075 0ustar apollockapollock# 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. """Implementations of in-order work deference.""" import abc import enum import threading from grpc.framework.foundation import activated from grpc.framework.foundation import logging_pool _NULL_BEHAVIOR = lambda unused_value: None class Relay(object): """Performs work submitted to it in another thread. Performs work in the order in which work was submitted to it; otherwise there would be no reason to use an implementation of this interface instead of a thread pool. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def add_value(self, value): """Adds a value to be passed to the behavior registered with this Relay. Args: value: A value that will be passed to a call made in another thread to the behavior registered with this Relay. """ raise NotImplementedError() @abc.abstractmethod def set_behavior(self, behavior): """Sets the behavior that this Relay should call when passed values. Args: behavior: The behavior that this Relay should call in another thread when passed a value, or None to have passed values ignored. """ raise NotImplementedError() class _PoolRelay(activated.Activated, Relay): @enum.unique class _State(enum.Enum): INACTIVE = 'inactive' IDLE = 'idle' SPINNING = 'spinning' def __init__(self, pool, behavior): self._condition = threading.Condition() self._pool = pool self._own_pool = pool is None self._state = _PoolRelay._State.INACTIVE self._activated = False self._spinning = False self._values = [] self._behavior = _NULL_BEHAVIOR if behavior is None else behavior def _spin(self, behavior, value): while True: behavior(value) with self._condition: if self._values: value = self._values.pop(0) behavior = self._behavior else: self._state = _PoolRelay._State.IDLE self._condition.notify_all() break def add_value(self, value): with self._condition: if self._state is _PoolRelay._State.INACTIVE: raise ValueError('add_value not valid on inactive Relay!') elif self._state is _PoolRelay._State.IDLE: self._pool.submit(self._spin, self._behavior, value) self._state = _PoolRelay._State.SPINNING else: self._values.append(value) def set_behavior(self, behavior): with self._condition: self._behavior = _NULL_BEHAVIOR if behavior is None else behavior def _start(self): with self._condition: self._state = _PoolRelay._State.IDLE if self._own_pool: self._pool = logging_pool.pool(1) return self def _stop(self): with self._condition: while self._state is _PoolRelay._State.SPINNING: self._condition.wait() if self._own_pool: self._pool.shutdown(wait=True) self._state = _PoolRelay._State.INACTIVE def __enter__(self): return self._start() def __exit__(self, exc_type, exc_val, exc_tb): self._stop() return False def start(self): return self._start() def stop(self): self._stop() def relay(behavior): """Creates a Relay. Args: behavior: The behavior to be called by the created Relay, or None to have passed values dropped until a different behavior is given to the returned Relay later. Returns: An object that is both an activated.Activated and a Relay. The object is only valid for use as a Relay when activated. """ return _PoolRelay(None, behavior) def pool_relay(pool, behavior): """Creates a Relay that uses a given thread pool. This object will make use of at most one thread in the given pool. Args: pool: A futures.ThreadPoolExecutor for use by the created Relay. behavior: The behavior to be called by the created Relay, or None to have passed values dropped until a different behavior is given to the returned Relay later. Returns: An object that is both an activated.Activated and a Relay. The object is only valid for use as a Relay when activated. """ return _PoolRelay(pool, behavior) grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/stream.py0000644000175000017500000000437012600663151025261 0ustar apollockapollock# 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. """Interfaces related to streams of values or objects.""" import abc class Consumer(object): """Interface for consumers of finite streams of values or objects.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def consume(self, value): """Accepts a value. Args: value: Any value accepted by this Consumer. """ raise NotImplementedError() @abc.abstractmethod def terminate(self): """Indicates to this Consumer that no more values will be supplied.""" raise NotImplementedError() @abc.abstractmethod def consume_and_terminate(self, value): """Supplies a value and signals that no more values will be supplied. Args: value: Any value accepted by this Consumer. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/abandonment.py0000644000175000017500000000343612600663151026256 0ustar apollockapollock# 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. """Utilities for indicating abandonment of computation.""" class Abandoned(Exception): """Indicates that some computation is being abandoned. Abandoning a computation is different than returning a value or raising an exception indicating some operational or programming defect. """ grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/later.py0000644000175000017500000000422512600663151025074 0ustar apollockapollock# 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. """Enables scheduling execution at a later time.""" import time from grpc.framework.foundation import _timer_future def later(delay, computation): """Schedules later execution of a callable. Args: delay: Any numeric value. Represents the minimum length of time in seconds to allow to pass before beginning the computation. No guarantees are made about the maximum length of time that will pass. computation: A callable that accepts no arguments. Returns: A Future representing the scheduled computation. """ timer_future = _timer_future.TimerFuture(time.time() + delay, computation) timer_future.start() return timer_future grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/activated.py0000644000175000017500000000457012600663151025734 0ustar apollockapollock# 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. """Interfaces related to streams of values or objects.""" import abc class Activated(object): """Interface for objects that may be started and stopped. Values implementing this type must also implement the context manager protocol. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def __enter__(self): """See the context manager protocol for specification.""" raise NotImplementedError() @abc.abstractmethod def __exit__(self, exc_type, exc_val, exc_tb): """See the context manager protocol for specification.""" raise NotImplementedError() @abc.abstractmethod def start(self): """Activates this object. Returns: A value equal to the value returned by this object's __enter__ method. """ raise NotImplementedError() @abc.abstractmethod def stop(self): """Deactivates this object.""" raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/__init__.py0000644000175000017500000000277212600663151025531 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/callable_util.py0000644000175000017500000000756112600663151026567 0ustar apollockapollock# 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. """Utilities for working with callables.""" import abc import collections import enum import functools import logging class Outcome(object): """A sum type describing the outcome of some call. Attributes: kind: One of Kind.RETURNED or Kind.RAISED respectively indicating that the call returned a value or raised an exception. return_value: The value returned by the call. Must be present if kind is Kind.RETURNED. exception: The exception raised by the call. Must be present if kind is Kind.RAISED. """ __metaclass__ = abc.ABCMeta @enum.unique class Kind(enum.Enum): """Identifies the general kind of the outcome of some call.""" RETURNED = object() RAISED = object() class _EasyOutcome( collections.namedtuple( '_EasyOutcome', ['kind', 'return_value', 'exception']), Outcome): """A trivial implementation of Outcome.""" def _call_logging_exceptions(behavior, message, *args, **kwargs): try: return _EasyOutcome(Outcome.Kind.RETURNED, behavior(*args, **kwargs), None) except Exception as e: # pylint: disable=broad-except logging.exception(message) return _EasyOutcome(Outcome.Kind.RAISED, None, e) def with_exceptions_logged(behavior, message): """Wraps a callable in a try-except that logs any exceptions it raises. Args: behavior: Any callable. message: A string to log if the behavior raises an exception. Returns: A callable that when executed invokes the given behavior. The returned callable takes the same arguments as the given behavior but returns a future.Outcome describing whether the given behavior returned a value or raised an exception. """ @functools.wraps(behavior) def wrapped_behavior(*args, **kwargs): return _call_logging_exceptions(behavior, message, *args, **kwargs) return wrapped_behavior def call_logging_exceptions(behavior, message, *args, **kwargs): """Calls a behavior in a try-except that logs any exceptions it raises. Args: behavior: Any callable. message: A string to log if the behavior raises an exception. *args: Positional arguments to pass to the given behavior. **kwargs: Keyword arguments to pass to the given behavior. Returns: An Outcome describing whether the given behavior returned a value or raised an exception. """ return _call_logging_exceptions(behavior, message, *args, **kwargs) grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/future.py0000644000175000017500000002126012600663151025275 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A Future interface. Python doesn't have a Future interface in its standard library. In the absence of such a standard, three separate, incompatible implementations (concurrent.futures.Future, ndb.Future, and asyncio.Future) have appeared. This interface attempts to be as compatible as possible with concurrent.futures.Future. From ndb.Future it adopts a traceback-object accessor method. Unlike the concrete and implemented Future classes listed above, the Future class defined in this module is an entirely abstract interface that anyone may implement and use. The one known incompatibility between this interface and the interface of concurrent.futures.Future is that this interface defines its own CancelledError and TimeoutError exceptions rather than raising the implementation-private concurrent.futures._base.CancelledError and the built-in-but-only-in-3.3-and-later TimeoutError. """ import abc class TimeoutError(Exception): """Indicates that a particular call timed out.""" class CancelledError(Exception): """Indicates that the computation underlying a Future was cancelled.""" class Future(object): """A representation of a computation in another control flow. Computations represented by a Future may be yet to be begun, may be ongoing, or may have already completed. """ __metaclass__ = abc.ABCMeta # NOTE(nathaniel): This isn't the return type that I would want to have if it # were up to me. Were this interface being written from scratch, the return # type of this method would probably be a sum type like: # # NOT_COMMENCED # COMMENCED_AND_NOT_COMPLETED # PARTIAL_RESULT # COMPLETED # UNCANCELLABLE # NOT_IMMEDIATELY_DETERMINABLE @abc.abstractmethod def cancel(self): """Attempts to cancel the computation. This method does not block. Returns: True if the computation has not yet begun, will not be allowed to take place, and determination of both was possible without blocking. False under all other circumstances including but not limited to the computation's already having begun, the computation's already having finished, and the computation's having been scheduled for execution on a remote system for which a determination of whether or not it commenced before being cancelled cannot be made without blocking. """ raise NotImplementedError() # NOTE(nathaniel): Here too this isn't the return type that I'd want this # method to have if it were up to me. I think I'd go with another sum type # like: # # NOT_CANCELLED (this object's cancel method hasn't been called) # NOT_COMMENCED # COMMENCED_AND_NOT_COMPLETED # PARTIAL_RESULT # COMPLETED # UNCANCELLABLE # NOT_IMMEDIATELY_DETERMINABLE # # Notice how giving the cancel method the right semantics obviates most # reasons for this method to exist. @abc.abstractmethod def cancelled(self): """Describes whether the computation was cancelled. This method does not block. Returns: True if the computation was cancelled any time before its result became immediately available. False under all other circumstances including but not limited to this object's cancel method not having been called and the computation's result having become immediately available. """ raise NotImplementedError() @abc.abstractmethod def running(self): """Describes whether the computation is taking place. This method does not block. Returns: True if the computation is scheduled to take place in the future or is taking place now, or False if the computation took place in the past or was cancelled. """ raise NotImplementedError() # NOTE(nathaniel): These aren't quite the semantics I'd like here either. I # would rather this only returned True in cases in which the underlying # computation completed successfully. A computation's having been cancelled # conflicts with considering that computation "done". @abc.abstractmethod def done(self): """Describes whether the computation has taken place. This method does not block. Returns: True if the computation is known to have either completed or have been unscheduled or interrupted. False if the computation may possibly be executing or scheduled to execute later. """ raise NotImplementedError() @abc.abstractmethod def result(self, timeout=None): """Accesses the outcome of the computation or raises its exception. This method may return immediately or may block. Args: timeout: The length of time in seconds to wait for the computation to finish or be cancelled, or None if this method should block until the computation has finished or is cancelled no matter how long that takes. Returns: The return value of the computation. Raises: TimeoutError: If a timeout value is passed and the computation does not terminate within the allotted time. CancelledError: If the computation was cancelled. Exception: If the computation raised an exception, this call will raise the same exception. """ raise NotImplementedError() @abc.abstractmethod def exception(self, timeout=None): """Return the exception raised by the computation. This method may return immediately or may block. Args: timeout: The length of time in seconds to wait for the computation to terminate or be cancelled, or None if this method should block until the computation is terminated or is cancelled no matter how long that takes. Returns: The exception raised by the computation, or None if the computation did not raise an exception. Raises: TimeoutError: If a timeout value is passed and the computation does not terminate within the allotted time. CancelledError: If the computation was cancelled. """ raise NotImplementedError() @abc.abstractmethod def traceback(self, timeout=None): """Access the traceback of the exception raised by the computation. This method may return immediately or may block. Args: timeout: The length of time in seconds to wait for the computation to terminate or be cancelled, or None if this method should block until the computation is terminated or is cancelled no matter how long that takes. Returns: The traceback of the exception raised by the computation, or None if the computation did not raise an exception. Raises: TimeoutError: If a timeout value is passed and the computation does not terminate within the allotted time. CancelledError: If the computation was cancelled. """ raise NotImplementedError() @abc.abstractmethod def add_done_callback(self, fn): """Adds a function to be called at completion of the computation. The callback will be passed this Future object describing the outcome of the computation. If the computation has already completed, the callback will be called immediately. Args: fn: A callable taking a this Future object as its single parameter. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/_timer_future.py0000644000175000017500000001536712600663151026647 0ustar apollockapollock# 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. """Affords a Future implementation based on Python's threading.Timer.""" import sys import threading import time from grpc.framework.foundation import future class TimerFuture(future.Future): """A Future implementation based around Timer objects.""" def __init__(self, compute_time, computation): """Constructor. Args: compute_time: The time after which to begin this future's computation. computation: The computation to be performed within this Future. """ self._lock = threading.Lock() self._compute_time = compute_time self._computation = computation self._timer = None self._computing = False self._computed = False self._cancelled = False self._result = None self._exception = None self._traceback = None self._waiting = [] def _compute(self): """Performs the computation embedded in this Future. Or doesn't, if the time to perform it has not yet arrived. """ with self._lock: time_remaining = self._compute_time - time.time() if 0 < time_remaining: self._timer = threading.Timer(time_remaining, self._compute) self._timer.start() return else: self._computing = True try: return_value = self._computation() exception = None traceback = None except Exception as e: # pylint: disable=broad-except return_value = None exception = e traceback = sys.exc_info()[2] with self._lock: self._computing = False self._computed = True self._return_value = return_value self._exception = exception self._traceback = traceback waiting = self._waiting for callback in waiting: callback(self) def start(self): """Starts this Future. This must be called exactly once, immediately after construction. """ with self._lock: self._timer = threading.Timer( self._compute_time - time.time(), self._compute) self._timer.start() def cancel(self): """See future.Future.cancel for specification.""" with self._lock: if self._computing or self._computed: return False elif self._cancelled: return True else: self._timer.cancel() self._cancelled = True waiting = self._waiting for callback in waiting: try: callback(self) except Exception: # pylint: disable=broad-except pass return True def cancelled(self): """See future.Future.cancelled for specification.""" with self._lock: return self._cancelled def running(self): """See future.Future.running for specification.""" with self._lock: return not self._computed and not self._cancelled def done(self): """See future.Future.done for specification.""" with self._lock: return self._computed or self._cancelled def result(self, timeout=None): """See future.Future.result for specification.""" with self._lock: if self._cancelled: raise future.CancelledError() elif self._computed: if self._exception is None: return self._return_value else: raise self._exception # pylint: disable=raising-bad-type condition = threading.Condition() def notify_condition(unused_future): with condition: condition.notify() self._waiting.append(notify_condition) with condition: condition.wait(timeout=timeout) with self._lock: if self._cancelled: raise future.CancelledError() elif self._computed: if self._exception is None: return self._return_value else: raise self._exception # pylint: disable=raising-bad-type else: raise future.TimeoutError() def exception(self, timeout=None): """See future.Future.exception for specification.""" with self._lock: if self._cancelled: raise future.CancelledError() elif self._computed: return self._exception condition = threading.Condition() def notify_condition(unused_future): with condition: condition.notify() self._waiting.append(notify_condition) with condition: condition.wait(timeout=timeout) with self._lock: if self._cancelled: raise future.CancelledError() elif self._computed: return self._exception else: raise future.TimeoutError() def traceback(self, timeout=None): """See future.Future.traceback for specification.""" with self._lock: if self._cancelled: raise future.CancelledError() elif self._computed: return self._traceback condition = threading.Condition() def notify_condition(unused_future): with condition: condition.notify() self._waiting.append(notify_condition) with condition: condition.wait(timeout=timeout) with self._lock: if self._cancelled: raise future.CancelledError() elif self._computed: return self._traceback else: raise future.TimeoutError() def add_done_callback(self, fn): """See future.Future.add_done_callback for specification.""" with self._lock: if not self._computed and not self._cancelled: self._waiting.append(fn) return fn(self) grpc-0.11.1/src/python/grpcio/grpc/framework/foundation/stream_util.py0000644000175000017500000001171612600663151026320 0ustar apollockapollock# 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. """Helpful utilities related to the stream module.""" import logging import threading from grpc.framework.foundation import stream _NO_VALUE = object() class TransformingConsumer(stream.Consumer): """A stream.Consumer that passes a transformation of its input to another.""" def __init__(self, transformation, downstream): self._transformation = transformation self._downstream = downstream def consume(self, value): self._downstream.consume(self._transformation(value)) def terminate(self): self._downstream.terminate() def consume_and_terminate(self, value): self._downstream.consume_and_terminate(self._transformation(value)) class IterableConsumer(stream.Consumer): """A Consumer that when iterated over emits the values it has consumed.""" def __init__(self): self._condition = threading.Condition() self._values = [] self._active = True def consume(self, stock_reply): with self._condition: if self._active: self._values.append(stock_reply) self._condition.notify() def terminate(self): with self._condition: self._active = False self._condition.notify() def consume_and_terminate(self, stock_reply): with self._condition: if self._active: self._values.append(stock_reply) self._active = False self._condition.notify() def __iter__(self): return self def next(self): with self._condition: while self._active and not self._values: self._condition.wait() if self._values: return self._values.pop(0) else: raise StopIteration() class ThreadSwitchingConsumer(stream.Consumer): """A Consumer decorator that affords serialization and asynchrony.""" def __init__(self, sink, pool): self._lock = threading.Lock() self._sink = sink self._pool = pool # True if self._spin has been submitted to the pool to be called once and # that call has not yet returned, False otherwise. self._spinning = False self._values = [] self._active = True def _spin(self, sink, value, terminate): while True: try: if value is _NO_VALUE: sink.terminate() elif terminate: sink.consume_and_terminate(value) else: sink.consume(value) except Exception as e: # pylint:disable=broad-except logging.exception(e) with self._lock: if terminate: self._spinning = False return elif self._values: value = self._values.pop(0) terminate = not self._values and not self._active elif not self._active: value = _NO_VALUE terminate = True else: self._spinning = False return def consume(self, value): with self._lock: if self._active: if self._spinning: self._values.append(value) else: self._pool.submit(self._spin, self._sink, value, False) self._spinning = True def terminate(self): with self._lock: if self._active: self._active = False if not self._spinning: self._pool.submit(self._spin, self._sink, _NO_VALUE, True) self._spinning = True def consume_and_terminate(self, value): with self._lock: if self._active: self._active = False if self._spinning: self._values.append(value) else: self._pool.submit(self._spin, self._sink, value, True) self._spinning = True grpc-0.11.1/src/python/grpcio/grpc/framework/crust/0000755000175000017500000000000012600663151022402 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/crust/_control.py0000644000175000017500000004734612600663151024611 0ustar apollockapollock# 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. """State and behavior for translating between sync and async control flow.""" import collections import enum import sys import threading import time from grpc.framework.foundation import abandonment from grpc.framework.foundation import callable_util from grpc.framework.foundation import future from grpc.framework.foundation import stream from grpc.framework.interfaces.base import base from grpc.framework.interfaces.base import utilities from grpc.framework.interfaces.face import face _DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!' _INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Crust) Internal Error! )-:' _CANNOT_SET_INITIAL_METADATA = ( 'Could not set initial metadata - has it already been set, or has a ' + 'payload already been sent?') _CANNOT_SET_TERMINAL_METADATA = ( 'Could not set terminal metadata - has it already been set, or has RPC ' + 'completion already been indicated?') _CANNOT_SET_CODE = ( 'Could not set code - has it already been set, or has RPC completion ' + 'already been indicated?') _CANNOT_SET_DETAILS = ( 'Could not set details - has it already been set, or has RPC completion ' + 'already been indicated?') class _DummyOperator(base.Operator): def advance( self, initial_metadata=None, payload=None, completion=None, allowance=None): pass _DUMMY_OPERATOR = _DummyOperator() class _Awaited( collections.namedtuple('_Awaited', ('kind', 'value',))): @enum.unique class Kind(enum.Enum): NOT_YET_ARRIVED = 'not yet arrived' ARRIVED = 'arrived' _NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None) _ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None) class _Transitory( collections.namedtuple('_Transitory', ('kind', 'value',))): @enum.unique class Kind(enum.Enum): NOT_YET_SEEN = 'not yet seen' PRESENT = 'present' GONE = 'gone' _NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None) _GONE = _Transitory(_Transitory.Kind.GONE, None) class _Termination( collections.namedtuple( '_Termination', ('terminated', 'abortion', 'abortion_error',))): """Values indicating whether and how an RPC has terminated. Attributes: terminated: A boolean indicating whether or not the RPC has terminated. abortion: A face.Abortion value describing the RPC's abortion or None if the RPC did not abort. abortion_error: A face.AbortionError describing the RPC's abortion or None if the RPC did not abort. """ _NOT_TERMINATED = _Termination(False, None, None) _OPERATION_OUTCOME_KIND_TO_TERMINATION_CONSTRUCTOR = { base.Outcome.Kind.COMPLETED: lambda *unused_args: _Termination( True, None, None), base.Outcome.Kind.CANCELLED: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.CANCELLED, *args), face.CancellationError(*args)), base.Outcome.Kind.EXPIRED: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.EXPIRED, *args), face.ExpirationError(*args)), base.Outcome.Kind.LOCAL_SHUTDOWN: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.LOCAL_SHUTDOWN, *args), face.LocalShutdownError(*args)), base.Outcome.Kind.REMOTE_SHUTDOWN: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.REMOTE_SHUTDOWN, *args), face.RemoteShutdownError(*args)), base.Outcome.Kind.RECEPTION_FAILURE: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args), face.NetworkError(*args)), base.Outcome.Kind.TRANSMISSION_FAILURE: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args), face.NetworkError(*args)), base.Outcome.Kind.LOCAL_FAILURE: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.LOCAL_FAILURE, *args), face.LocalError(*args)), base.Outcome.Kind.REMOTE_FAILURE: lambda *args: _Termination( True, face.Abortion(face.Abortion.Kind.REMOTE_FAILURE, *args), face.RemoteError(*args)), } def _wait_once_until(condition, until): if until is None: condition.wait() else: remaining = until - time.time() if remaining < 0: raise future.TimeoutError() else: condition.wait(timeout=remaining) def _done_callback_as_operation_termination_callback( done_callback, rendezvous): def operation_termination_callback(operation_outcome): rendezvous.set_outcome(operation_outcome) done_callback(rendezvous) return operation_termination_callback def _abortion_callback_as_operation_termination_callback( rpc_abortion_callback, rendezvous_set_outcome): def operation_termination_callback(operation_outcome): termination = rendezvous_set_outcome(operation_outcome) if termination.abortion is not None: rpc_abortion_callback(termination.abortion) return operation_termination_callback class Rendezvous(base.Operator, future.Future, stream.Consumer, face.Call): """A rendez-vous for the threads of an operation. Instances of this object present iterator and stream.Consumer interfaces for interacting with application code and present a base.Operator interface and maintain a base.Operator internally for interacting with base interface code. """ def __init__(self, operator, operation_context): self._condition = threading.Condition() self._operator = operator self._operation_context = operation_context self._protocol_context = _NOT_YET_ARRIVED self._up_initial_metadata = _NOT_YET_ARRIVED self._up_payload = None self._up_allowance = 1 self._up_completion = _NOT_YET_ARRIVED self._down_initial_metadata = _NOT_YET_SEEN self._down_payload = None self._down_allowance = 1 self._down_terminal_metadata = _NOT_YET_SEEN self._down_code = _NOT_YET_SEEN self._down_details = _NOT_YET_SEEN self._termination = _NOT_TERMINATED # The semantics of future.Future.cancel and future.Future.cancelled are # slightly wonky, so they have to be tracked separately from the rest of the # result of the RPC. This field tracks whether cancellation was requested # prior to termination of the RPC self._cancelled = False def set_operator_and_context(self, operator, operation_context): with self._condition: self._operator = operator self._operation_context = operation_context def _down_completion(self): if self._down_terminal_metadata.kind is _Transitory.Kind.NOT_YET_SEEN: terminal_metadata = None self._down_terminal_metadata = _GONE elif self._down_terminal_metadata.kind is _Transitory.Kind.PRESENT: terminal_metadata = self._down_terminal_metadata.value self._down_terminal_metadata = _GONE else: terminal_metadata = None if self._down_code.kind is _Transitory.Kind.NOT_YET_SEEN: code = None self._down_code = _GONE elif self._down_code.kind is _Transitory.Kind.PRESENT: code = self._down_code.value self._down_code = _GONE else: code = None if self._down_details.kind is _Transitory.Kind.NOT_YET_SEEN: details = None self._down_details = _GONE elif self._down_details.kind is _Transitory.Kind.PRESENT: details = self._down_details.value self._down_details = _GONE else: details = None return utilities.completion(terminal_metadata, code, details) def _set_outcome(self, outcome): if not self._termination.terminated: self._operator = _DUMMY_OPERATOR self._operation_context = None self._down_initial_metadata = _GONE self._down_payload = None self._down_terminal_metadata = _GONE self._down_code = _GONE self._down_details = _GONE if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED: initial_metadata = None else: initial_metadata = self._up_initial_metadata.value if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED: terminal_metadata = None else: terminal_metadata = self._up_completion.value.terminal_metadata if outcome.kind is base.Outcome.Kind.COMPLETED: code = self._up_completion.value.code details = self._up_completion.value.message else: code = outcome.code details = outcome.details self._termination = _OPERATION_OUTCOME_KIND_TO_TERMINATION_CONSTRUCTOR[ outcome.kind](initial_metadata, terminal_metadata, code, details) self._condition.notify_all() return self._termination def advance( self, initial_metadata=None, payload=None, completion=None, allowance=None): with self._condition: if initial_metadata is not None: self._up_initial_metadata = _Awaited( _Awaited.Kind.ARRIVED, initial_metadata) if payload is not None: if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED: self._up_initial_metadata = _ARRIVED_AND_NONE self._up_payload = payload self._up_allowance -= 1 if completion is not None: if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED: self._up_initial_metadata = _ARRIVED_AND_NONE self._up_completion = _Awaited( _Awaited.Kind.ARRIVED, completion) if allowance is not None: if self._down_payload is not None: self._operator.advance(payload=self._down_payload) self._down_payload = None self._down_allowance += allowance - 1 else: self._down_allowance += allowance self._condition.notify_all() def cancel(self): with self._condition: if self._operation_context is not None: self._operation_context.cancel() self._cancelled = True return False def cancelled(self): with self._condition: return self._cancelled def running(self): with self._condition: return not self._termination.terminated def done(self): with self._condition: return self._termination.terminated def result(self, timeout=None): until = None if timeout is None else time.time() + timeout with self._condition: while True: if self._termination.terminated: if self._termination.abortion is None: return self._up_payload elif self._termination.abortion.kind is face.Abortion.Kind.CANCELLED: raise future.CancelledError() else: raise self._termination.abortion_error # pylint: disable=raising-bad-type else: _wait_once_until(self._condition, until) def exception(self, timeout=None): until = None if timeout is None else time.time() + timeout with self._condition: while True: if self._termination.terminated: if self._termination.abortion is None: return None else: return self._termination.abortion_error else: _wait_once_until(self._condition, until) def traceback(self, timeout=None): until = None if timeout is None else time.time() + timeout with self._condition: while True: if self._termination.terminated: if self._termination.abortion_error is None: return None else: abortion_error = self._termination.abortion_error break else: _wait_once_until(self._condition, until) try: raise abortion_error except face.AbortionError: return sys.exc_info()[2] def add_done_callback(self, fn): with self._condition: if self._operation_context is not None: outcome = self._operation_context.add_termination_callback( _done_callback_as_operation_termination_callback(fn, self)) if outcome is None: return else: self._set_outcome(outcome) fn(self) def consume(self, value): with self._condition: while True: if self._termination.terminated: return elif 0 < self._down_allowance: self._operator.advance(payload=value) self._down_allowance -= 1 return else: self._condition.wait() def terminate(self): with self._condition: if self._termination.terminated: return elif self._down_code.kind is _Transitory.Kind.GONE: # Conform to specified idempotence of terminate by ignoring extra calls. return else: completion = self._down_completion() self._operator.advance(completion=completion) def consume_and_terminate(self, value): with self._condition: while True: if self._termination.terminated: return elif 0 < self._down_allowance: completion = self._down_completion() self._operator.advance(payload=value, completion=completion) return else: self._condition.wait() def __iter__(self): return self def next(self): with self._condition: while True: if self._termination.abortion_error is not None: raise self._termination.abortion_error elif self._up_payload is not None: payload = self._up_payload self._up_payload = None if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED: self._operator.advance(allowance=1) return payload elif self._up_completion.kind is _Awaited.Kind.ARRIVED: raise StopIteration() else: self._condition.wait() def is_active(self): with self._condition: return not self._termination.terminated def time_remaining(self): if self._operation_context is None: return 0 else: return self._operation_context.time_remaining() def add_abortion_callback(self, abortion_callback): with self._condition: if self._operation_context is None: return self._termination.abortion else: outcome = self._operation_context.add_termination_callback( _abortion_callback_as_operation_termination_callback( abortion_callback, self.set_outcome)) if outcome is not None: return self._set_outcome(outcome).abortion else: return self._termination.abortion def protocol_context(self): with self._condition: while True: if self._protocol_context.kind is _Awaited.Kind.ARRIVED: return self._protocol_context.value elif self._termination.abortion_error is not None: raise self._termination.abortion_error else: self._condition.wait() def initial_metadata(self): with self._condition: while True: if self._up_initial_metadata.kind is _Awaited.Kind.ARRIVED: return self._up_initial_metadata.value elif self._termination.terminated: return None else: self._condition.wait() def terminal_metadata(self): with self._condition: while True: if self._up_completion.kind is _Awaited.Kind.ARRIVED: return self._up_completion.value.terminal_metadata elif self._termination.terminated: return None else: self._condition.wait() def code(self): with self._condition: while True: if self._up_completion.kind is _Awaited.Kind.ARRIVED: return self._up_completion.value.code elif self._termination.terminated: return None else: self._condition.wait() def details(self): with self._condition: while True: if self._up_completion.kind is _Awaited.Kind.ARRIVED: return self._up_completion.value.message elif self._termination.terminated: return None else: self._condition.wait() def set_initial_metadata(self, initial_metadata): with self._condition: if (self._down_initial_metadata.kind is not _Transitory.Kind.NOT_YET_SEEN): raise ValueError(_CANNOT_SET_INITIAL_METADATA) else: self._down_initial_metadata = _GONE self._operator.advance(initial_metadata=initial_metadata) def set_terminal_metadata(self, terminal_metadata): with self._condition: if (self._down_terminal_metadata.kind is not _Transitory.Kind.NOT_YET_SEEN): raise ValueError(_CANNOT_SET_TERMINAL_METADATA) else: self._down_terminal_metadata = _Transitory( _Transitory.Kind.PRESENT, terminal_metadata) def set_code(self, code): with self._condition: if self._down_code.kind is not _Transitory.Kind.NOT_YET_SEEN: raise ValueError(_CANNOT_SET_CODE) else: self._down_code = _Transitory(_Transitory.Kind.PRESENT, code) def set_details(self, details): with self._condition: if self._down_details.kind is not _Transitory.Kind.NOT_YET_SEEN: raise ValueError(_CANNOT_SET_DETAILS) else: self._down_details = _Transitory(_Transitory.Kind.PRESENT, details) def set_protocol_context(self, protocol_context): with self._condition: self._protocol_context = _Awaited( _Awaited.Kind.ARRIVED, protocol_context) self._condition.notify_all() def set_outcome(self, outcome): with self._condition: return self._set_outcome(outcome) class _ProtocolReceiver(base.ProtocolReceiver): def __init__(self, rendezvous): self._rendezvous = rendezvous def context(self, protocol_context): self._rendezvous.set_protocol_context(protocol_context) def protocol_receiver(rendezvous): return _ProtocolReceiver(rendezvous) def pool_wrap(behavior, operation_context): """Wraps an operation-related behavior so that it may be called in a pool. Args: behavior: A callable related to carrying out an operation. operation_context: A base_interfaces.OperationContext for the operation. Returns: A callable that when called carries out the behavior of the given callable and handles whatever exceptions it raises appropriately. """ def translation(*args): try: behavior(*args) except ( abandonment.Abandoned, face.CancellationError, face.ExpirationError, face.LocalShutdownError, face.RemoteShutdownError, face.NetworkError, face.RemoteError, ) as e: if operation_context.outcome() is None: operation_context.fail(e) except Exception as e: operation_context.fail(e) return callable_util.with_exceptions_logged( translation, _INTERNAL_ERROR_LOG_MESSAGE) grpc-0.11.1/src/python/grpcio/grpc/framework/crust/implementations.py0000644000175000017500000003452412600663151026174 0ustar apollockapollock# 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. """Entry points into the Crust layer of RPC Framework.""" from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.crust import _calls from grpc.framework.crust import _service from grpc.framework.interfaces.base import base from grpc.framework.interfaces.face import face class _BaseServicer(base.Servicer): def __init__(self, adapted_methods, adapted_multi_method): self._adapted_methods = adapted_methods self._adapted_multi_method = adapted_multi_method def service(self, group, method, context, output_operator): adapted_method = self._adapted_methods.get((group, method), None) if adapted_method is not None: return adapted_method(output_operator, context) elif self._adapted_multi_method is not None: try: return self._adapted_multi_method( group, method, output_operator, context) except face.NoSuchMethodError: raise base.NoSuchMethodError(None, None) else: raise base.NoSuchMethodError(None, None) class _UnaryUnaryMultiCallable(face.UnaryUnaryMultiCallable): def __init__(self, end, group, method, pool): self._end = end self._group = group self._method = method self._pool = pool def __call__( self, request, timeout, metadata=None, with_call=False, protocol_options=None): return _calls.blocking_unary_unary( self._end, self._group, self._method, timeout, with_call, protocol_options, metadata, request) def future(self, request, timeout, metadata=None, protocol_options=None): return _calls.future_unary_unary( self._end, self._group, self._method, timeout, protocol_options, metadata, request) def event( self, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_unary_unary( self._end, self._group, self._method, timeout, protocol_options, metadata, request, receiver, abortion_callback, self._pool) class _UnaryStreamMultiCallable(face.UnaryStreamMultiCallable): def __init__(self, end, group, method, pool): self._end = end self._group = group self._method = method self._pool = pool def __call__(self, request, timeout, metadata=None, protocol_options=None): return _calls.inline_unary_stream( self._end, self._group, self._method, timeout, protocol_options, metadata, request) def event( self, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_unary_stream( self._end, self._group, self._method, timeout, protocol_options, metadata, request, receiver, abortion_callback, self._pool) class _StreamUnaryMultiCallable(face.StreamUnaryMultiCallable): def __init__(self, end, group, method, pool): self._end = end self._group = group self._method = method self._pool = pool def __call__( self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None): return _calls.blocking_stream_unary( self._end, self._group, self._method, timeout, with_call, protocol_options, metadata, request_iterator, self._pool) def future( self, request_iterator, timeout, metadata=None, protocol_options=None): return _calls.future_stream_unary( self._end, self._group, self._method, timeout, protocol_options, metadata, request_iterator, self._pool) def event( self, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_stream_unary( self._end, self._group, self._method, timeout, protocol_options, metadata, receiver, abortion_callback, self._pool) class _StreamStreamMultiCallable(face.StreamStreamMultiCallable): def __init__(self, end, group, method, pool): self._end = end self._group = group self._method = method self._pool = pool def __call__( self, request_iterator, timeout, metadata=None, protocol_options=None): return _calls.inline_stream_stream( self._end, self._group, self._method, timeout, protocol_options, metadata, request_iterator, self._pool) def event( self, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_stream_stream( self._end, self._group, self._method, timeout, protocol_options, metadata, receiver, abortion_callback, self._pool) class _GenericStub(face.GenericStub): """An face.GenericStub implementation.""" def __init__(self, end, pool): self._end = end self._pool = pool def blocking_unary_unary( self, group, method, request, timeout, metadata=None, with_call=None, protocol_options=None): return _calls.blocking_unary_unary( self._end, group, method, timeout, with_call, protocol_options, metadata, request) def future_unary_unary( self, group, method, request, timeout, metadata=None, protocol_options=None): return _calls.future_unary_unary( self._end, group, method, timeout, protocol_options, metadata, request) def inline_unary_stream( self, group, method, request, timeout, metadata=None, protocol_options=None): return _calls.inline_unary_stream( self._end, group, method, timeout, protocol_options, metadata, request) def blocking_stream_unary( self, group, method, request_iterator, timeout, metadata=None, with_call=None, protocol_options=None): return _calls.blocking_stream_unary( self._end, group, method, timeout, with_call, protocol_options, metadata, request_iterator, self._pool) def future_stream_unary( self, group, method, request_iterator, timeout, metadata=None, protocol_options=None): return _calls.future_stream_unary( self._end, group, method, timeout, protocol_options, metadata, request_iterator, self._pool) def inline_stream_stream( self, group, method, request_iterator, timeout, metadata=None, protocol_options=None): return _calls.inline_stream_stream( self._end, group, method, timeout, protocol_options, metadata, request_iterator, self._pool) def event_unary_unary( self, group, method, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_unary_unary( self._end, group, method, timeout, protocol_options, metadata, request, receiver, abortion_callback, self._pool) def event_unary_stream( self, group, method, request, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_unary_stream( self._end, group, method, timeout, protocol_options, metadata, request, receiver, abortion_callback, self._pool) def event_stream_unary( self, group, method, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_stream_unary( self._end, group, method, timeout, protocol_options, metadata, receiver, abortion_callback, self._pool) def event_stream_stream( self, group, method, receiver, abortion_callback, timeout, metadata=None, protocol_options=None): return _calls.event_stream_stream( self._end, group, method, timeout, protocol_options, metadata, receiver, abortion_callback, self._pool) def unary_unary(self, group, method): return _UnaryUnaryMultiCallable(self._end, group, method, self._pool) def unary_stream(self, group, method): return _UnaryStreamMultiCallable(self._end, group, method, self._pool) def stream_unary(self, group, method): return _StreamUnaryMultiCallable(self._end, group, method, self._pool) def stream_stream(self, group, method): return _StreamStreamMultiCallable(self._end, group, method, self._pool) class _DynamicStub(face.DynamicStub): """An face.DynamicStub implementation.""" def __init__(self, end, group, cardinalities, pool): self._end = end self._group = group self._cardinalities = cardinalities self._pool = pool def __getattr__(self, attr): method_cardinality = self._cardinalities.get(attr) if method_cardinality is cardinality.Cardinality.UNARY_UNARY: return _UnaryUnaryMultiCallable(self._end, self._group, attr, self._pool) elif method_cardinality is cardinality.Cardinality.UNARY_STREAM: return _UnaryStreamMultiCallable(self._end, self._group, attr, self._pool) elif method_cardinality is cardinality.Cardinality.STREAM_UNARY: return _StreamUnaryMultiCallable(self._end, self._group, attr, self._pool) elif method_cardinality is cardinality.Cardinality.STREAM_STREAM: return _StreamStreamMultiCallable( self._end, self._group, attr, self._pool) else: raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr) def _adapt_method_implementations(method_implementations, pool): adapted_implementations = {} for name, method_implementation in method_implementations.iteritems(): if method_implementation.style is style.Service.INLINE: if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: adapted_implementations[name] = _service.adapt_inline_unary_unary( method_implementation.unary_unary_inline, pool) elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM: adapted_implementations[name] = _service.adapt_inline_unary_stream( method_implementation.unary_stream_inline, pool) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY: adapted_implementations[name] = _service.adapt_inline_stream_unary( method_implementation.stream_unary_inline, pool) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM: adapted_implementations[name] = _service.adapt_inline_stream_stream( method_implementation.stream_stream_inline, pool) elif method_implementation.style is style.Service.EVENT: if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: adapted_implementations[name] = _service.adapt_event_unary_unary( method_implementation.unary_unary_event, pool) elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM: adapted_implementations[name] = _service.adapt_event_unary_stream( method_implementation.unary_stream_event, pool) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY: adapted_implementations[name] = _service.adapt_event_stream_unary( method_implementation.stream_unary_event, pool) elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM: adapted_implementations[name] = _service.adapt_event_stream_stream( method_implementation.stream_stream_event, pool) return adapted_implementations def servicer(method_implementations, multi_method_implementation, pool): """Creates a base.Servicer. It is guaranteed that any passed face.MultiMethodImplementation will only be called to service an RPC if there is no face.MethodImplementation for the RPC method in the passed method_implementations dictionary. Args: method_implementations: A dictionary from RPC method name to face.MethodImplementation object to be used to service the named RPC method. multi_method_implementation: An face.MultiMethodImplementation to be used to service any RPCs not serviced by the face.MethodImplementations given in the method_implementations dictionary, or None. pool: A thread pool. Returns: A base.Servicer that services RPCs via the given implementations. """ adapted_implementations = _adapt_method_implementations( method_implementations, pool) if multi_method_implementation is None: adapted_multi_method_implementation = None else: adapted_multi_method_implementation = _service.adapt_multi_method( multi_method_implementation, pool) return _BaseServicer( adapted_implementations, adapted_multi_method_implementation) def generic_stub(end, pool): """Creates an face.GenericStub. Args: end: A base.End. pool: A futures.ThreadPoolExecutor. Returns: A face.GenericStub that performs RPCs via the given base.End. """ return _GenericStub(end, pool) def dynamic_stub(end, group, cardinalities, pool): """Creates an face.DynamicStub. Args: end: A base.End. group: The group identifier for all RPCs to be made with the created face.DynamicStub. cardinalities: A dict from method identifier to cardinality.Cardinality value identifying the cardinality of every RPC method to be supported by the created face.DynamicStub. pool: A futures.ThreadPoolExecutor. Returns: A face.DynamicStub that performs RPCs via the given base.End. """ return _DynamicStub(end, group, cardinalities, pool) grpc-0.11.1/src/python/grpcio/grpc/framework/crust/_calls.py0000644000175000017500000002065512600663151024221 0ustar apollockapollock# 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. """Utility functions for invoking RPCs.""" from grpc.framework.crust import _control from grpc.framework.interfaces.base import utilities from grpc.framework.interfaces.face import face _ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!' _EMPTY_COMPLETION = utilities.completion(None, None, None) def _invoke( end, group, method, timeout, protocol_options, initial_metadata, payload, complete): rendezvous = _control.Rendezvous(None, None) subscription = utilities.full_subscription( rendezvous, _control.protocol_receiver(rendezvous)) operation_context, operator = end.operate( group, method, subscription, timeout, protocol_options=protocol_options, initial_metadata=initial_metadata, payload=payload, completion=_EMPTY_COMPLETION if complete else None) rendezvous.set_operator_and_context(operator, operation_context) outcome = operation_context.add_termination_callback(rendezvous.set_outcome) if outcome is not None: rendezvous.set_outcome(outcome) return rendezvous, operation_context, outcome def _event_return_unary( receiver, abortion_callback, rendezvous, operation_context, outcome, pool): if outcome is None: def in_pool(): abortion = rendezvous.add_abortion_callback(abortion_callback) if abortion is None: try: receiver.initial_metadata(rendezvous.initial_metadata()) receiver.response(next(rendezvous)) receiver.complete( rendezvous.terminal_metadata(), rendezvous.code(), rendezvous.details()) except face.AbortionError: pass else: abortion_callback(abortion) pool.submit(_control.pool_wrap(in_pool, operation_context)) return rendezvous def _event_return_stream( receiver, abortion_callback, rendezvous, operation_context, outcome, pool): if outcome is None: def in_pool(): abortion = rendezvous.add_abortion_callback(abortion_callback) if abortion is None: try: receiver.initial_metadata(rendezvous.initial_metadata()) for response in rendezvous: receiver.response(response) receiver.complete( rendezvous.terminal_metadata(), rendezvous.code(), rendezvous.details()) except face.AbortionError: pass else: abortion_callback(abortion) pool.submit(_control.pool_wrap(in_pool, operation_context)) return rendezvous def blocking_unary_unary( end, group, method, timeout, with_call, protocol_options, initial_metadata, payload): """Services in a blocking fashion a unary-unary servicer method.""" rendezvous, unused_operation_context, unused_outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, payload, True) if with_call: return next(rendezvous), rendezvous else: return next(rendezvous) def future_unary_unary( end, group, method, timeout, protocol_options, initial_metadata, payload): """Services a value-in value-out servicer method by returning a Future.""" rendezvous, unused_operation_context, unused_outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, payload, True) return rendezvous def inline_unary_stream( end, group, method, timeout, protocol_options, initial_metadata, payload): """Services a value-in stream-out servicer method.""" rendezvous, unused_operation_context, unused_outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, payload, True) return rendezvous def blocking_stream_unary( end, group, method, timeout, with_call, protocol_options, initial_metadata, payload_iterator, pool): """Services in a blocking fashion a stream-in value-out servicer method.""" rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, None, False) if outcome is None: def in_pool(): for payload in payload_iterator: rendezvous.consume(payload) rendezvous.terminate() pool.submit(_control.pool_wrap(in_pool, operation_context)) if with_call: return next(rendezvous), rendezvous else: return next(rendezvous) else: if with_call: return next(rendezvous), rendezvous else: return next(rendezvous) def future_stream_unary( end, group, method, timeout, protocol_options, initial_metadata, payload_iterator, pool): """Services a stream-in value-out servicer method by returning a Future.""" rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, None, False) if outcome is None: def in_pool(): for payload in payload_iterator: rendezvous.consume(payload) rendezvous.terminate() pool.submit(_control.pool_wrap(in_pool, operation_context)) return rendezvous def inline_stream_stream( end, group, method, timeout, protocol_options, initial_metadata, payload_iterator, pool): """Services a stream-in stream-out servicer method.""" rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, None, False) if outcome is None: def in_pool(): for payload in payload_iterator: rendezvous.consume(payload) rendezvous.terminate() pool.submit(_control.pool_wrap(in_pool, operation_context)) return rendezvous def event_unary_unary( end, group, method, timeout, protocol_options, initial_metadata, payload, receiver, abortion_callback, pool): rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, payload, True) return _event_return_unary( receiver, abortion_callback, rendezvous, operation_context, outcome, pool) def event_unary_stream( end, group, method, timeout, protocol_options, initial_metadata, payload, receiver, abortion_callback, pool): rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, payload, True) return _event_return_stream( receiver, abortion_callback, rendezvous, operation_context, outcome, pool) def event_stream_unary( end, group, method, timeout, protocol_options, initial_metadata, receiver, abortion_callback, pool): rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, None, False) return _event_return_unary( receiver, abortion_callback, rendezvous, operation_context, outcome, pool) def event_stream_stream( end, group, method, timeout, protocol_options, initial_metadata, receiver, abortion_callback, pool): rendezvous, operation_context, outcome = _invoke( end, group, method, timeout, protocol_options, initial_metadata, None, False) return _event_return_stream( receiver, abortion_callback, rendezvous, operation_context, outcome, pool) grpc-0.11.1/src/python/grpcio/grpc/framework/crust/__init__.py0000644000175000017500000000277212600663151024523 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/crust/_service.py0000644000175000017500000001400412600663151024552 0ustar apollockapollock# 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. """Behaviors for servicing RPCs.""" from grpc.framework.crust import _control from grpc.framework.foundation import abandonment from grpc.framework.interfaces.base import utilities from grpc.framework.interfaces.face import face class _ServicerContext(face.ServicerContext): def __init__(self, rendezvous): self._rendezvous = rendezvous def is_active(self): return self._rendezvous.is_active() def time_remaining(self): return self._rendezvous.time_remaining() def add_abortion_callback(self, abortion_callback): return self._rendezvous.add_abortion_callback(abortion_callback) def cancel(self): self._rendezvous.cancel() def protocol_context(self): return self._rendezvous.protocol_context() def invocation_metadata(self): return self._rendezvous.initial_metadata() def initial_metadata(self, initial_metadata): self._rendezvous.set_initial_metadata(initial_metadata) def terminal_metadata(self, terminal_metadata): self._rendezvous.set_terminal_metadata(terminal_metadata) def code(self, code): self._rendezvous.set_code(code) def details(self, details): self._rendezvous.set_details(details) def _adaptation(pool, in_pool): def adaptation(operator, operation_context): rendezvous = _control.Rendezvous(operator, operation_context) subscription = utilities.full_subscription( rendezvous, _control.protocol_receiver(rendezvous)) outcome = operation_context.add_termination_callback(rendezvous.set_outcome) if outcome is None: pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous) return subscription else: raise abandonment.Abandoned() return adaptation def adapt_inline_unary_unary(method, pool): def in_pool(rendezvous): request = next(rendezvous) response = method(request, _ServicerContext(rendezvous)) rendezvous.consume_and_terminate(response) return _adaptation(pool, in_pool) def adapt_inline_unary_stream(method, pool): def in_pool(rendezvous): request = next(rendezvous) response_iterator = method(request, _ServicerContext(rendezvous)) for response in response_iterator: rendezvous.consume(response) rendezvous.terminate() return _adaptation(pool, in_pool) def adapt_inline_stream_unary(method, pool): def in_pool(rendezvous): response = method(rendezvous, _ServicerContext(rendezvous)) rendezvous.consume_and_terminate(response) return _adaptation(pool, in_pool) def adapt_inline_stream_stream(method, pool): def in_pool(rendezvous): response_iterator = method(rendezvous, _ServicerContext(rendezvous)) for response in response_iterator: rendezvous.consume(response) rendezvous.terminate() return _adaptation(pool, in_pool) def adapt_event_unary_unary(method, pool): def in_pool(rendezvous): request = next(rendezvous) method( request, rendezvous.consume_and_terminate, _ServicerContext(rendezvous)) return _adaptation(pool, in_pool) def adapt_event_unary_stream(method, pool): def in_pool(rendezvous): request = next(rendezvous) method(request, rendezvous, _ServicerContext(rendezvous)) return _adaptation(pool, in_pool) def adapt_event_stream_unary(method, pool): def in_pool(rendezvous): request_consumer = method( rendezvous.consume_and_terminate, _ServicerContext(rendezvous)) for request in rendezvous: request_consumer.consume(request) request_consumer.terminate() return _adaptation(pool, in_pool) def adapt_event_stream_stream(method, pool): def in_pool(rendezvous): request_consumer = method(rendezvous, _ServicerContext(rendezvous)) for request in rendezvous: request_consumer.consume(request) request_consumer.terminate() return _adaptation(pool, in_pool) def adapt_multi_method(multi_method, pool): def adaptation(group, method, operator, operation_context): rendezvous = _control.Rendezvous(operator, operation_context) subscription = utilities.full_subscription( rendezvous, _control.protocol_receiver(rendezvous)) outcome = operation_context.add_termination_callback(rendezvous.set_outcome) if outcome is None: def in_pool(): request_consumer = multi_method.service( group, method, rendezvous, _ServicerContext(rendezvous)) for request in rendezvous: request_consumer.consume(request) request_consumer.terminate() pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous) return subscription else: raise abandonment.Abandoned() return adaptation grpc-0.11.1/src/python/grpcio/grpc/framework/base/0000755000175000017500000000000012600663151022154 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/framework/base/_ingestion.py0000644000175000017500000004003712600663151024670 0ustar apollockapollock# 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. """State and behavior for ingestion during an operation.""" import abc import collections from grpc.framework.base import _constants from grpc.framework.base import _interfaces from grpc.framework.base import exceptions from grpc.framework.base import interfaces from grpc.framework.foundation import abandonment from grpc.framework.foundation import callable_util from grpc.framework.foundation import stream _CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!' _CONSUME_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!' class _ConsumerCreation(collections.namedtuple( '_ConsumerCreation', ('consumer', 'remote_error', 'abandoned'))): """A sum type for the outcome of ingestion initialization. Either consumer will be non-None, remote_error will be True, or abandoned will be True. Attributes: consumer: A stream.Consumer for ingesting payloads. remote_error: A boolean indicating that the consumer could not be created due to an error on the remote side of the operation. abandoned: A boolean indicating that the consumer creation was abandoned. """ class _EmptyConsumer(stream.Consumer): """A no-operative stream.Consumer that ignores all inputs and calls.""" def consume(self, value): """See stream.Consumer.consume for specification.""" def terminate(self): """See stream.Consumer.terminate for specification.""" def consume_and_terminate(self, value): """See stream.Consumer.consume_and_terminate for specification.""" class _ConsumerCreator(object): """Common specification of different consumer-creating behavior.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def create_consumer(self, requirement): """Creates the stream.Consumer to which customer payloads will be delivered. Any exceptions raised by this method should be attributed to and treated as defects in the serviced or servicer code called by this method. Args: requirement: A value required by this _ConsumerCreator for consumer creation. Returns: A _ConsumerCreation describing the result of consumer creation. """ raise NotImplementedError() class _FrontConsumerCreator(_ConsumerCreator): """A _ConsumerCreator appropriate for front-side use.""" def __init__(self, subscription, operation_context): """Constructor. Args: subscription: The serviced's interfaces.ServicedSubscription for the operation. operation_context: The interfaces.OperationContext object for the operation. """ self._subscription = subscription self._operation_context = operation_context def create_consumer(self, requirement): """See _ConsumerCreator.create_consumer for specification.""" if self._subscription.kind is interfaces.ServicedSubscription.Kind.FULL: try: return _ConsumerCreation( self._subscription.ingestor.consumer(self._operation_context), False, False) except abandonment.Abandoned: return _ConsumerCreation(None, False, True) else: return _ConsumerCreation(_EmptyConsumer(), False, False) class _BackConsumerCreator(_ConsumerCreator): """A _ConsumerCreator appropriate for back-side use.""" def __init__(self, servicer, operation_context, emission_consumer): """Constructor. Args: servicer: The interfaces.Servicer that will service the operation. operation_context: The interfaces.OperationContext object for the operation. emission_consumer: The stream.Consumer object to which payloads emitted from the operation will be passed. """ self._servicer = servicer self._operation_context = operation_context self._emission_consumer = emission_consumer def create_consumer(self, requirement): """See _ConsumerCreator.create_consumer for full specification. Args: requirement: The name of the Servicer method to be called during this operation. Returns: A _ConsumerCreation describing the result of consumer creation. """ try: return _ConsumerCreation( self._servicer.service( requirement, self._operation_context, self._emission_consumer), False, False) except exceptions.NoSuchMethodError: return _ConsumerCreation(None, True, False) except abandonment.Abandoned: return _ConsumerCreation(None, False, True) class _WrappedConsumer(object): """Wraps a consumer to catch the exceptions that it is allowed to throw.""" def __init__(self, consumer): """Constructor. Args: consumer: A stream.Consumer that may raise abandonment.Abandoned from any of its methods. """ self._consumer = consumer def moar(self, payload, complete): """Makes progress with the wrapped consumer. This method catches all exceptions allowed to be thrown by the wrapped consumer. Any exceptions raised by this method should be blamed on the customer-supplied consumer. Args: payload: A customer-significant payload object. May be None only if complete is True. complete: Whether or not the end of the payload sequence has been reached. Must be True if payload is None. Returns: True if the wrapped consumer made progress or False if the wrapped consumer raised abandonment.Abandoned to indicate its abandonment of progress. """ try: if payload is None: self._consumer.terminate() elif complete: self._consumer.consume_and_terminate(payload) else: self._consumer.consume(payload) return True except abandonment.Abandoned: return False class _IngestionManager(_interfaces.IngestionManager): """An implementation of _interfaces.IngestionManager.""" def __init__( self, lock, pool, consumer_creator, failure_outcome, termination_manager, transmission_manager): """Constructor. Args: lock: The operation-wide lock. pool: A thread pool in which to execute customer code. consumer_creator: A _ConsumerCreator wrapping the portion of customer code that when called returns the stream.Consumer with which the customer code will ingest payload values. failure_outcome: Whichever one of interfaces.Outcome.SERVICED_FAILURE or interfaces.Outcome.SERVICER_FAILURE describes local failure of customer code. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. """ self._lock = lock self._pool = pool self._consumer_creator = consumer_creator self._failure_outcome = failure_outcome self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._expiration_manager = None self._wrapped_ingestion_consumer = None self._pending_ingestion = [] self._ingestion_complete = False self._processing = False def set_expiration_manager(self, expiration_manager): self._expiration_manager = expiration_manager def _abort_internal_only(self): self._wrapped_ingestion_consumer = None self._pending_ingestion = None def _abort_and_notify(self, outcome): self._abort_internal_only() self._termination_manager.abort(outcome) self._transmission_manager.abort(outcome) self._expiration_manager.abort() def _next(self): """Computes the next step for ingestion. Returns: A payload, complete, continue triplet indicating what payload (if any) is available to feed into customer code, whether or not the sequence of payloads has terminated, and whether or not there is anything immediately actionable to call customer code to do. """ if self._pending_ingestion is None: return None, False, False elif self._pending_ingestion: payload = self._pending_ingestion.pop(0) complete = self._ingestion_complete and not self._pending_ingestion return payload, complete, True elif self._ingestion_complete: return None, True, True else: return None, False, False def _process(self, wrapped_ingestion_consumer, payload, complete): """A method to call to execute customer code. This object's lock must *not* be held when calling this method. Args: wrapped_ingestion_consumer: The _WrappedConsumer with which to pass payloads to customer code. payload: A customer payload. May be None only if complete is True. complete: Whether or not the sequence of payloads to pass to the customer has concluded. """ while True: consumption_outcome = callable_util.call_logging_exceptions( wrapped_ingestion_consumer.moar, _CONSUME_EXCEPTION_LOG_MESSAGE, payload, complete) if consumption_outcome.exception is None: if consumption_outcome.return_value: with self._lock: if complete: self._pending_ingestion = None self._termination_manager.ingestion_complete() return else: payload, complete, moar = self._next() if not moar: self._processing = False return else: with self._lock: if self._pending_ingestion is not None: self._abort_and_notify(self._failure_outcome) self._processing = False return else: with self._lock: self._abort_and_notify(self._failure_outcome) self._processing = False return def start(self, requirement): if self._pending_ingestion is not None: def initialize(): consumer_creation_outcome = callable_util.call_logging_exceptions( self._consumer_creator.create_consumer, _CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE, requirement) if consumer_creation_outcome.return_value is None: with self._lock: self._abort_and_notify(self._failure_outcome) self._processing = False elif consumer_creation_outcome.return_value.remote_error: with self._lock: self._abort_and_notify(interfaces.Outcome.RECEPTION_FAILURE) self._processing = False elif consumer_creation_outcome.return_value.abandoned: with self._lock: if self._pending_ingestion is not None: self._abort_and_notify(self._failure_outcome) self._processing = False else: wrapped_ingestion_consumer = _WrappedConsumer( consumer_creation_outcome.return_value.consumer) with self._lock: self._wrapped_ingestion_consumer = wrapped_ingestion_consumer payload, complete, moar = self._next() if not moar: self._processing = False return self._process(wrapped_ingestion_consumer, payload, complete) self._pool.submit( callable_util.with_exceptions_logged( initialize, _constants.INTERNAL_ERROR_LOG_MESSAGE)) self._processing = True def consume(self, payload): if self._ingestion_complete: self._abort_and_notify(self._failure_outcome) elif self._pending_ingestion is not None: if self._processing: self._pending_ingestion.append(payload) else: self._pool.submit( callable_util.with_exceptions_logged( self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE), self._wrapped_ingestion_consumer, payload, False) self._processing = True def terminate(self): if self._ingestion_complete: self._abort_and_notify(self._failure_outcome) else: self._ingestion_complete = True if self._pending_ingestion is not None and not self._processing: self._pool.submit( callable_util.with_exceptions_logged( self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE), self._wrapped_ingestion_consumer, None, True) self._processing = True def consume_and_terminate(self, payload): if self._ingestion_complete: self._abort_and_notify(self._failure_outcome) else: self._ingestion_complete = True if self._pending_ingestion is not None: if self._processing: self._pending_ingestion.append(payload) else: self._pool.submit( callable_util.with_exceptions_logged( self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE), self._wrapped_ingestion_consumer, payload, True) self._processing = True def abort(self): """See _interfaces.IngestionManager.abort for specification.""" self._abort_internal_only() def front_ingestion_manager( lock, pool, subscription, termination_manager, transmission_manager, operation_context): """Creates an IngestionManager appropriate for front-side use. Args: lock: The operation-wide lock. pool: A thread pool in which to execute customer code. subscription: A interfaces.ServicedSubscription indicating the customer's interest in the results of the operation. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. operation_context: A interfaces.OperationContext for the operation. Returns: An IngestionManager appropriate for front-side use. """ ingestion_manager = _IngestionManager( lock, pool, _FrontConsumerCreator(subscription, operation_context), interfaces.Outcome.SERVICED_FAILURE, termination_manager, transmission_manager) ingestion_manager.start(None) return ingestion_manager def back_ingestion_manager( lock, pool, servicer, termination_manager, transmission_manager, operation_context, emission_consumer): """Creates an IngestionManager appropriate for back-side use. Args: lock: The operation-wide lock. pool: A thread pool in which to execute customer code. servicer: A interfaces.Servicer for servicing the operation. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. operation_context: A interfaces.OperationContext for the operation. emission_consumer: The _interfaces.EmissionConsumer for the operation. Returns: An IngestionManager appropriate for back-side use. """ ingestion_manager = _IngestionManager( lock, pool, _BackConsumerCreator( servicer, operation_context, emission_consumer), interfaces.Outcome.SERVICER_FAILURE, termination_manager, transmission_manager) return ingestion_manager grpc-0.11.1/src/python/grpcio/grpc/framework/base/exceptions.py0000644000175000017500000000326412600663151024714 0ustar apollockapollock# 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. """Exceptions defined and used by the base layer of RPC Framework.""" class NoSuchMethodError(Exception): """Indicates that an operation with an unrecognized name has been called.""" grpc-0.11.1/src/python/grpcio/grpc/framework/base/_expiration.py0000644000175000017500000001430212600663151025047 0ustar apollockapollock# 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. """State and behavior for operation expiration.""" import time from grpc.framework.base import _interfaces from grpc.framework.base import interfaces from grpc.framework.foundation import later class _ExpirationManager(_interfaces.ExpirationManager): """An implementation of _interfaces.ExpirationManager.""" def __init__( self, lock, termination_manager, transmission_manager, ingestion_manager, commencement, timeout, maximum_timeout): """Constructor. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. ingestion_manager: The _interfaces.IngestionManager for the operation. commencement: The time in seconds since the epoch at which the operation began. timeout: A length of time in seconds to allow for the operation to run. maximum_timeout: The maximum length of time in seconds to allow for the operation to run despite what is requested via this object's change_timout method. """ self._lock = lock self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._ingestion_manager = ingestion_manager self._commencement = commencement self._maximum_timeout = maximum_timeout self._timeout = timeout self._deadline = commencement + timeout self._index = None self._future = None def _expire(self, index): with self._lock: if self._future is not None and index == self._index: self._future = None self._termination_manager.abort(interfaces.Outcome.EXPIRED) self._transmission_manager.abort(interfaces.Outcome.EXPIRED) self._ingestion_manager.abort() def start(self): self._index = 0 self._future = later.later(self._timeout, lambda: self._expire(0)) def change_timeout(self, timeout): if self._future is not None and timeout != self._timeout: self._future.cancel() new_timeout = min(timeout, self._maximum_timeout) new_index = self._index + 1 self._timeout = new_timeout self._deadline = self._commencement + new_timeout self._index = new_index delay = self._deadline - time.time() self._future = later.later( delay, lambda: self._expire(new_index)) def deadline(self): return self._deadline def abort(self): if self._future: self._future.cancel() self._future = None self._deadline_index = None def front_expiration_manager( lock, termination_manager, transmission_manager, ingestion_manager, timeout): """Creates an _interfaces.ExpirationManager appropriate for front-side use. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. ingestion_manager: The _interfaces.IngestionManager for the operation. timeout: A length of time in seconds to allow for the operation to run. Returns: An _interfaces.ExpirationManager appropriate for front-side use. """ commencement = time.time() expiration_manager = _ExpirationManager( lock, termination_manager, transmission_manager, ingestion_manager, commencement, timeout, timeout) expiration_manager.start() return expiration_manager def back_expiration_manager( lock, termination_manager, transmission_manager, ingestion_manager, timeout, default_timeout, maximum_timeout): """Creates an _interfaces.ExpirationManager appropriate for back-side use. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. ingestion_manager: The _interfaces.IngestionManager for the operation. timeout: A length of time in seconds to allow for the operation to run. May be None in which case default_timeout will be used. default_timeout: The default length of time in seconds to allow for the operation to run if the front-side customer has not specified such a value (or if the value they specified is not yet known). maximum_timeout: The maximum length of time in seconds to allow for the operation to run. Returns: An _interfaces.ExpirationManager appropriate for back-side use. """ commencement = time.time() expiration_manager = _ExpirationManager( lock, termination_manager, transmission_manager, ingestion_manager, commencement, default_timeout if timeout is None else timeout, maximum_timeout) expiration_manager.start() return expiration_manager grpc-0.11.1/src/python/grpcio/grpc/framework/base/_constants.py0000644000175000017500000000315712600663151024707 0ustar apollockapollock# 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. """Private constants for the package.""" INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Base) internal error! :-(' grpc-0.11.1/src/python/grpcio/grpc/framework/base/util.py0000644000175000017500000000654412600663151023514 0ustar apollockapollock# 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. """Utilities helpful for working with the base layer of RPC Framework.""" import collections import threading from grpc.framework.base import interfaces class _ServicedSubscription( collections.namedtuple('_ServicedSubscription', ['kind', 'ingestor']), interfaces.ServicedSubscription): """See interfaces.ServicedSubscription for specification.""" _NONE_SUBSCRIPTION = _ServicedSubscription( interfaces.ServicedSubscription.Kind.NONE, None) _TERMINATION_ONLY_SUBSCRIPTION = _ServicedSubscription( interfaces.ServicedSubscription.Kind.TERMINATION_ONLY, None) def none_serviced_subscription(): """Creates a "none" interfaces.ServicedSubscription object. Returns: An interfaces.ServicedSubscription indicating no subscription to an operation's results (such as would be the case for a fire-and-forget operation invocation). """ return _NONE_SUBSCRIPTION def termination_only_serviced_subscription(): """Creates a "termination only" interfaces.ServicedSubscription object. Returns: An interfaces.ServicedSubscription indicating that the front-side customer is interested only in the overall termination outcome of the operation (such as completion or expiration) and would ignore the actual results of the operation. """ return _TERMINATION_ONLY_SUBSCRIPTION def full_serviced_subscription(ingestor): """Creates a "full" interfaces.ServicedSubscription object. Args: ingestor: An interfaces.ServicedIngestor. Returns: An interfaces.ServicedSubscription object indicating a full subscription. """ return _ServicedSubscription( interfaces.ServicedSubscription.Kind.FULL, ingestor) def wait_for_idle(end): """Waits for an interfaces.End to complete all operations. Args: end: Any interfaces.End. """ event = threading.Event() end.add_idle_action(event.set) event.wait() grpc-0.11.1/src/python/grpcio/grpc/framework/base/interfaces.py0000644000175000017500000002755412600663151024666 0ustar apollockapollock# 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. """Interfaces defined and used by the base layer of RPC Framework.""" import abc import collections import enum # stream is referenced from specification in this module. from grpc.framework.foundation import stream # pylint: disable=unused-import @enum.unique class Outcome(enum.Enum): """Operation outcomes.""" COMPLETED = 'completed' CANCELLED = 'cancelled' EXPIRED = 'expired' RECEPTION_FAILURE = 'reception failure' TRANSMISSION_FAILURE = 'transmission failure' SERVICER_FAILURE = 'servicer failure' SERVICED_FAILURE = 'serviced failure' class OperationContext(object): """Provides operation-related information and action. Attributes: trace_id: A uuid.UUID identifying a particular set of related operations. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def is_active(self): """Describes whether the operation is active or has terminated.""" raise NotImplementedError() @abc.abstractmethod def add_termination_callback(self, callback): """Adds a function to be called upon operation termination. Args: callback: A callable that will be passed an Outcome value. """ raise NotImplementedError() @abc.abstractmethod def time_remaining(self): """Describes the length of allowed time remaining for the operation. Returns: A nonnegative float indicating the length of allowed time in seconds remaining for the operation to complete before it is considered to have timed out. """ raise NotImplementedError() @abc.abstractmethod def fail(self, exception): """Indicates that the operation has failed. Args: exception: An exception germane to the operation failure. May be None. """ raise NotImplementedError() class Servicer(object): """Interface for service implementations.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, name, context, output_consumer): """Services an operation. Args: name: The name of the operation. context: A ServicerContext object affording contextual information and actions. output_consumer: A stream.Consumer that will accept output values of the operation. Returns: A stream.Consumer that will accept input values for the operation. Raises: exceptions.NoSuchMethodError: If this Servicer affords no method with the given name. abandonment.Abandoned: If the operation has been aborted and there no longer is any reason to service the operation. """ raise NotImplementedError() class Operation(object): """Representation of an in-progress operation. Attributes: consumer: A stream.Consumer into which payloads constituting the operation's input may be passed. context: An OperationContext affording information and action about the operation. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def cancel(self): """Cancels this operation.""" raise NotImplementedError() class ServicedIngestor(object): """Responsible for accepting the result of an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def consumer(self, operation_context): """Affords a consumer to which operation results will be passed. Args: operation_context: An OperationContext object for the current operation. Returns: A stream.Consumer to which the results of the current operation will be passed. Raises: abandonment.Abandoned: If the operation has been aborted and there no longer is any reason to service the operation. """ raise NotImplementedError() class ServicedSubscription(object): """A sum type representing a serviced's interest in an operation. Attributes: kind: A Kind value. ingestor: A ServicedIngestor. Must be present if kind is Kind.FULL. Must be None if kind is Kind.TERMINATION_ONLY or Kind.NONE. """ __metaclass__ = abc.ABCMeta @enum.unique class Kind(enum.Enum): """Kinds of subscription.""" FULL = 'full' TERMINATION_ONLY = 'termination only' NONE = 'none' class End(object): """Common type for entry-point objects on both sides of an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def operation_stats(self): """Reports the number of terminated operations broken down by outcome. Returns: A dictionary from Outcome value to an integer identifying the number of operations that terminated with that outcome. """ raise NotImplementedError() @abc.abstractmethod def add_idle_action(self, action): """Adds an action to be called when this End has no ongoing operations. Args: action: A callable that accepts no arguments. """ raise NotImplementedError() class Front(End): """Clientish objects that afford the invocation of operations.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def operate( self, name, payload, complete, timeout, subscription, trace_id): """Commences an operation. Args: name: The name of the method invoked for the operation. payload: An initial payload for the operation. May be None. complete: A boolean indicating whether or not additional payloads to be sent to the servicer may be supplied after this call. timeout: A length of time in seconds to allow for the operation. subscription: A ServicedSubscription for the operation. trace_id: A uuid.UUID identifying a set of related operations to which this operation belongs. Returns: An Operation object affording information and action about the operation in progress. """ raise NotImplementedError() class Back(End): """Serverish objects that perform the work of operations.""" __metaclass__ = abc.ABCMeta class FrontToBackTicket( collections.namedtuple( 'FrontToBackTicket', ['operation_id', 'sequence_number', 'kind', 'name', 'subscription', 'trace_id', 'payload', 'timeout'])): """A sum type for all values sent from a front to a back. Attributes: operation_id: A unique-with-respect-to-equality hashable object identifying a particular operation. sequence_number: A zero-indexed integer sequence number identifying the ticket's place among all the tickets sent from front to back for this particular operation. Must be zero if kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be positive for any other kind. kind: A Kind value describing the overall kind of ticket. name: The name of an operation. Must be present if kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be None for any other kind. subscription: An ServicedSubscription.Kind value describing the interest the front has in tickets sent from the back. Must be present if kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be None for any other kind. trace_id: A uuid.UUID identifying a set of related operations to which this operation belongs. May be None. payload: A customer payload object. Must be present if kind is Kind.CONTINUATION. Must be None if kind is Kind.CANCELLATION. May be None for any other kind. timeout: An optional length of time (measured from the beginning of the operation) to allow for the entire operation. If None, a default value on the back will be used. If present and excessively large, the back may limit the operation to a smaller duration of its choice. May be present for any ticket kind; setting a value on a later ticket allows fronts to request time extensions (or even time reductions!) on in-progress operations. """ @enum.unique class Kind(enum.Enum): """Identifies the overall kind of a FrontToBackTicket.""" COMMENCEMENT = 'commencement' CONTINUATION = 'continuation' COMPLETION = 'completion' ENTIRE = 'entire' CANCELLATION = 'cancellation' EXPIRATION = 'expiration' SERVICER_FAILURE = 'servicer failure' SERVICED_FAILURE = 'serviced failure' RECEPTION_FAILURE = 'reception failure' TRANSMISSION_FAILURE = 'transmission failure' class BackToFrontTicket( collections.namedtuple( 'BackToFrontTicket', ['operation_id', 'sequence_number', 'kind', 'payload'])): """A sum type for all values sent from a back to a front. Attributes: operation_id: A unique-with-respect-to-equality hashable object identifying a particular operation. sequence_number: A zero-indexed integer sequence number identifying the ticket's place among all the tickets sent from back to front for this particular operation. kind: A Kind value describing the overall kind of ticket. payload: A customer payload object. Must be present if kind is Kind.CONTINUATION. May be None if kind is Kind.COMPLETION. Must be None otherwise. """ @enum.unique class Kind(enum.Enum): """Identifies the overall kind of a BackToFrontTicket.""" CONTINUATION = 'continuation' COMPLETION = 'completion' CANCELLATION = 'cancellation' EXPIRATION = 'expiration' SERVICER_FAILURE = 'servicer failure' SERVICED_FAILURE = 'serviced failure' RECEPTION_FAILURE = 'reception failure' TRANSMISSION_FAILURE = 'transmission failure' class ForeLink(object): """Accepts back-to-front tickets and emits front-to-back tickets.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def accept_back_to_front_ticket(self, ticket): """Accept a BackToFrontTicket. Args: ticket: Any BackToFrontTicket. """ raise NotImplementedError() @abc.abstractmethod def join_rear_link(self, rear_link): """Mates this object with a peer with which it will exchange tickets.""" raise NotImplementedError() class RearLink(object): """Accepts front-to-back tickets and emits back-to-front tickets.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def accept_front_to_back_ticket(self, ticket): """Accepts a FrontToBackTicket. Args: ticket: Any FrontToBackTicket. """ raise NotImplementedError() @abc.abstractmethod def join_fore_link(self, fore_link): """Mates this object with a peer with which it will exchange tickets.""" raise NotImplementedError() class FrontLink(Front, ForeLink): """Clientish objects that operate by sending and receiving tickets.""" __metaclass__ = abc.ABCMeta class BackLink(Back, RearLink): """Serverish objects that operate by sending and receiving tickets.""" __metaclass__ = abc.ABCMeta grpc-0.11.1/src/python/grpcio/grpc/framework/base/implementations.py0000644000175000017500000000644512600663151025747 0ustar apollockapollock# 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. """Entry points into the ticket-exchange-based base layer implementation.""" # interfaces is referenced from specification in this module. from grpc.framework.base import _ends from grpc.framework.base import interfaces # pylint: disable=unused-import def front_link(work_pool, transmission_pool, utility_pool): """Factory function for creating interfaces.FrontLinks. Args: work_pool: A thread pool to be used for doing work within the created FrontLink object. transmission_pool: A thread pool to be used within the created FrontLink object for transmitting values to a joined RearLink object. utility_pool: A thread pool to be used within the created FrontLink object for utility tasks. Returns: An interfaces.FrontLink. """ return _ends.FrontLink(work_pool, transmission_pool, utility_pool) def back_link( servicer, work_pool, transmission_pool, utility_pool, default_timeout, maximum_timeout): """Factory function for creating interfaces.BackLinks. Args: servicer: An interfaces.Servicer for servicing operations. work_pool: A thread pool to be used for doing work within the created BackLink object. transmission_pool: A thread pool to be used within the created BackLink object for transmitting values to a joined ForeLink object. utility_pool: A thread pool to be used within the created BackLink object for utility tasks. default_timeout: A length of time in seconds to be used as the default time alloted for a single operation. maximum_timeout: A length of time in seconds to be used as the maximum time alloted for a single operation. Returns: An interfaces.BackLink. """ return _ends.BackLink( servicer, work_pool, transmission_pool, utility_pool, default_timeout, maximum_timeout) grpc-0.11.1/src/python/grpcio/grpc/framework/base/null.py0000644000175000017500000000407212600663151023503 0ustar apollockapollock# 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. """Null links that ignore tickets passed to them.""" from grpc.framework.base import interfaces class _NullForeLink(interfaces.ForeLink): """A do-nothing ForeLink.""" def accept_back_to_front_ticket(self, ticket): pass def join_rear_link(self, rear_link): raise NotImplementedError() class _NullRearLink(interfaces.RearLink): """A do-nothing RearLink.""" def accept_front_to_back_ticket(self, ticket): pass def join_fore_link(self, fore_link): raise NotImplementedError() NULL_FORE_LINK = _NullForeLink() NULL_REAR_LINK = _NullRearLink() grpc-0.11.1/src/python/grpcio/grpc/framework/base/_emission.py0000644000175000017500000001136212600663151024516 0ustar apollockapollock# 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. """State and behavior for handling emitted values.""" from grpc.framework.base import interfaces from grpc.framework.base import _interfaces class _EmissionManager(_interfaces.EmissionManager): """An implementation of _interfaces.EmissionManager.""" def __init__( self, lock, failure_outcome, termination_manager, transmission_manager): """Constructor. Args: lock: The operation-wide lock. failure_outcome: Whichever one of interfaces.Outcome.SERVICED_FAILURE or interfaces.Outcome.SERVICER_FAILURE describes this object's methods being called inappropriately by customer code. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. """ self._lock = lock self._failure_outcome = failure_outcome self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._ingestion_manager = None self._expiration_manager = None self._emission_complete = False def set_ingestion_manager_and_expiration_manager( self, ingestion_manager, expiration_manager): self._ingestion_manager = ingestion_manager self._expiration_manager = expiration_manager def _abort(self): self._termination_manager.abort(self._failure_outcome) self._transmission_manager.abort(self._failure_outcome) self._ingestion_manager.abort() self._expiration_manager.abort() def consume(self, value): with self._lock: if self._emission_complete: self._abort() else: self._transmission_manager.inmit(value, False) def terminate(self): with self._lock: if not self._emission_complete: self._termination_manager.emission_complete() self._transmission_manager.inmit(None, True) self._emission_complete = True def consume_and_terminate(self, value): with self._lock: if self._emission_complete: self._abort() else: self._termination_manager.emission_complete() self._transmission_manager.inmit(value, True) self._emission_complete = True def front_emission_manager(lock, termination_manager, transmission_manager): """Creates an _interfaces.EmissionManager appropriate for front-side use. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. Returns: An _interfaces.EmissionManager appropriate for front-side use. """ return _EmissionManager( lock, interfaces.Outcome.SERVICED_FAILURE, termination_manager, transmission_manager) def back_emission_manager(lock, termination_manager, transmission_manager): """Creates an _interfaces.EmissionManager appropriate for back-side use. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. Returns: An _interfaces.EmissionManager appropriate for back-side use. """ return _EmissionManager( lock, interfaces.Outcome.SERVICER_FAILURE, termination_manager, transmission_manager) grpc-0.11.1/src/python/grpcio/grpc/framework/base/_termination.py0000644000175000017500000001727012600663151025225 0ustar apollockapollock# 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. """State and behavior for operation termination.""" import enum from grpc.framework.base import _constants from grpc.framework.base import _interfaces from grpc.framework.base import interfaces from grpc.framework.foundation import callable_util _CALLBACK_EXCEPTION_LOG_MESSAGE = 'Exception calling termination callback!' @enum.unique class _Requirement(enum.Enum): """Symbols indicating events required for termination.""" EMISSION = 'emission' TRANSMISSION = 'transmission' INGESTION = 'ingestion' _FRONT_NOT_LISTENING_REQUIREMENTS = (_Requirement.TRANSMISSION,) _BACK_NOT_LISTENING_REQUIREMENTS = ( _Requirement.EMISSION, _Requirement.INGESTION,) _LISTENING_REQUIREMENTS = ( _Requirement.TRANSMISSION, _Requirement.INGESTION,) class _TerminationManager(_interfaces.TerminationManager): """An implementation of _interfaces.TerminationManager.""" def __init__( self, work_pool, utility_pool, action, requirements, local_failure): """Constructor. Args: work_pool: A thread pool in which customer work will be done. utility_pool: A thread pool in which work utility work will be done. action: An action to call on operation termination. requirements: A combination of _Requirement values identifying what must finish for the operation to be considered completed. local_failure: An interfaces.Outcome specifying what constitutes local failure of customer work. """ self._work_pool = work_pool self._utility_pool = utility_pool self._action = action self._local_failure = local_failure self._has_locally_failed = False self._expiration_manager = None self._outstanding_requirements = set(requirements) self._outcome = None self._callbacks = [] def set_expiration_manager(self, expiration_manager): self._expiration_manager = expiration_manager def _terminate(self, outcome): """Terminates the operation. Args: outcome: An interfaces.Outcome describing the outcome of the operation. """ self._expiration_manager.abort() self._outstanding_requirements = None callbacks = list(self._callbacks) self._callbacks = None self._outcome = outcome act = callable_util.with_exceptions_logged( self._action, _constants.INTERNAL_ERROR_LOG_MESSAGE) if self._has_locally_failed: self._utility_pool.submit(act, outcome) else: def call_callbacks_and_act(callbacks, outcome): for callback in callbacks: callback_outcome = callable_util.call_logging_exceptions( callback, _CALLBACK_EXCEPTION_LOG_MESSAGE, outcome) if callback_outcome.exception is not None: outcome = self._local_failure break self._utility_pool.submit(act, outcome) self._work_pool.submit(callable_util.with_exceptions_logged( call_callbacks_and_act, _constants.INTERNAL_ERROR_LOG_MESSAGE), callbacks, outcome) def is_active(self): """See _interfaces.TerminationManager.is_active for specification.""" return self._outstanding_requirements is not None def add_callback(self, callback): """See _interfaces.TerminationManager.add_callback for specification.""" if not self._has_locally_failed: if self._outstanding_requirements is None: self._work_pool.submit( callable_util.with_exceptions_logged( callback, _CALLBACK_EXCEPTION_LOG_MESSAGE), self._outcome) else: self._callbacks.append(callback) def emission_complete(self): """See superclass method for specification.""" if self._outstanding_requirements is not None: self._outstanding_requirements.discard(_Requirement.EMISSION) if not self._outstanding_requirements: self._terminate(interfaces.Outcome.COMPLETED) def transmission_complete(self): """See superclass method for specification.""" if self._outstanding_requirements is not None: self._outstanding_requirements.discard(_Requirement.TRANSMISSION) if not self._outstanding_requirements: self._terminate(interfaces.Outcome.COMPLETED) def ingestion_complete(self): """See superclass method for specification.""" if self._outstanding_requirements is not None: self._outstanding_requirements.discard(_Requirement.INGESTION) if not self._outstanding_requirements: self._terminate(interfaces.Outcome.COMPLETED) def abort(self, outcome): """See _interfaces.TerminationManager.abort for specification.""" if outcome is self._local_failure: self._has_failed_locally = True if self._outstanding_requirements is not None: self._terminate(outcome) def front_termination_manager( work_pool, utility_pool, action, subscription_kind): """Creates a TerminationManager appropriate for front-side use. Args: work_pool: A thread pool in which customer work will be done. utility_pool: A thread pool in which work utility work will be done. action: An action to call on operation termination. subscription_kind: An interfaces.ServicedSubscription.Kind value. Returns: A TerminationManager appropriate for front-side use. """ if subscription_kind is interfaces.ServicedSubscription.Kind.NONE: requirements = _FRONT_NOT_LISTENING_REQUIREMENTS else: requirements = _LISTENING_REQUIREMENTS return _TerminationManager( work_pool, utility_pool, action, requirements, interfaces.Outcome.SERVICED_FAILURE) def back_termination_manager(work_pool, utility_pool, action, subscription_kind): """Creates a TerminationManager appropriate for back-side use. Args: work_pool: A thread pool in which customer work will be done. utility_pool: A thread pool in which work utility work will be done. action: An action to call on operation termination. subscription_kind: An interfaces.ServicedSubscription.Kind value. Returns: A TerminationManager appropriate for back-side use. """ if subscription_kind is interfaces.ServicedSubscription.Kind.NONE: requirements = _BACK_NOT_LISTENING_REQUIREMENTS else: requirements = _LISTENING_REQUIREMENTS return _TerminationManager( work_pool, utility_pool, action, requirements, interfaces.Outcome.SERVICER_FAILURE) grpc-0.11.1/src/python/grpcio/grpc/framework/base/__init__.py0000644000175000017500000000277212600663151024275 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/framework/base/_ends.py0000644000175000017500000004027312600663151023624 0ustar apollockapollock# 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. """Implementations of FrontLinks and BackLinks.""" import collections import threading import uuid # _interfaces is referenced from specification in this module. from grpc.framework.base import _cancellation from grpc.framework.base import _context from grpc.framework.base import _emission from grpc.framework.base import _expiration from grpc.framework.base import _ingestion from grpc.framework.base import _interfaces # pylint: disable=unused-import from grpc.framework.base import _reception from grpc.framework.base import _termination from grpc.framework.base import _transmission from grpc.framework.base import interfaces from grpc.framework.foundation import callable_util _IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!' class _EasyOperation(interfaces.Operation): """A trivial implementation of interfaces.Operation.""" def __init__(self, emission_manager, context, cancellation_manager): """Constructor. Args: emission_manager: The _interfaces.EmissionManager for the operation that will accept values emitted by customer code. context: The interfaces.OperationContext for use by the customer during the operation. cancellation_manager: The _interfaces.CancellationManager for the operation. """ self.consumer = emission_manager self.context = context self._cancellation_manager = cancellation_manager def cancel(self): self._cancellation_manager.cancel() class _Endlette(object): """Utility for stateful behavior common to Fronts and Backs.""" def __init__(self, pool): """Constructor. Args: pool: A thread pool to use when calling registered idle actions. """ self._lock = threading.Lock() self._pool = pool # Dictionary from operation IDs to ReceptionManager-or-None. A None value # indicates an in-progress fire-and-forget operation for which the customer # has chosen to ignore results. self._operations = {} self._stats = {outcome: 0 for outcome in interfaces.Outcome} self._idle_actions = [] def terminal_action(self, operation_id): """Constructs the termination action for a single operation. Args: operation_id: An operation ID. Returns: A callable that takes an operation outcome for an argument to be used as the termination action for the operation associated with the given operation ID. """ def termination_action(outcome): with self._lock: self._stats[outcome] += 1 self._operations.pop(operation_id, None) if not self._operations: for action in self._idle_actions: self._pool.submit(callable_util.with_exceptions_logged( action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE)) self._idle_actions = [] return termination_action def __enter__(self): self._lock.acquire() def __exit__(self, exc_type, exc_val, exc_tb): self._lock.release() def get_operation(self, operation_id): return self._operations.get(operation_id, None) def add_operation(self, operation_id, operation_reception_manager): self._operations[operation_id] = operation_reception_manager def operation_stats(self): with self._lock: return dict(self._stats) def add_idle_action(self, action): with self._lock: if self._operations: self._idle_actions.append(action) else: self._pool.submit(callable_util.with_exceptions_logged( action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE)) class _FrontManagement( collections.namedtuple( '_FrontManagement', ('reception', 'emission', 'operation', 'cancellation'))): """Just a trivial helper class to bundle four fellow-traveling objects.""" def _front_operate( callback, work_pool, transmission_pool, utility_pool, termination_action, operation_id, name, payload, complete, timeout, subscription, trace_id): """Constructs objects necessary for front-side operation management. Args: callback: A callable that accepts interfaces.FrontToBackTickets and delivers them to the other side of the operation. Execution of this callable may take any arbitrary length of time. work_pool: A thread pool in which to execute customer code. transmission_pool: A thread pool to use for transmitting to the other side of the operation. utility_pool: A thread pool for utility tasks. termination_action: A no-arg behavior to be called upon operation completion. operation_id: An object identifying the operation. name: The name of the method being called during the operation. payload: The first customer-significant value to be transmitted to the other side. May be None if there is no such value or if the customer chose not to pass it at operation invocation. complete: A boolean indicating whether or not additional payloads will be supplied by the customer. timeout: A length of time in seconds to allow for the operation. subscription: A interfaces.ServicedSubscription describing the customer's interest in the results of the operation. trace_id: A uuid.UUID identifying a set of related operations to which this operation belongs. May be None. Returns: A _FrontManagement object bundling together the _interfaces.ReceptionManager, _interfaces.EmissionManager, _context.OperationContext, and _interfaces.CancellationManager for the operation. """ lock = threading.Lock() with lock: termination_manager = _termination.front_termination_manager( work_pool, utility_pool, termination_action, subscription.kind) transmission_manager = _transmission.front_transmission_manager( lock, transmission_pool, callback, operation_id, name, subscription.kind, trace_id, timeout, termination_manager) operation_context = _context.OperationContext( lock, operation_id, interfaces.Outcome.SERVICED_FAILURE, termination_manager, transmission_manager) emission_manager = _emission.front_emission_manager( lock, termination_manager, transmission_manager) ingestion_manager = _ingestion.front_ingestion_manager( lock, work_pool, subscription, termination_manager, transmission_manager, operation_context) expiration_manager = _expiration.front_expiration_manager( lock, termination_manager, transmission_manager, ingestion_manager, timeout) reception_manager = _reception.front_reception_manager( lock, termination_manager, transmission_manager, ingestion_manager, expiration_manager) cancellation_manager = _cancellation.CancellationManager( lock, termination_manager, transmission_manager, ingestion_manager, expiration_manager) termination_manager.set_expiration_manager(expiration_manager) transmission_manager.set_ingestion_and_expiration_managers( ingestion_manager, expiration_manager) operation_context.set_ingestion_and_expiration_managers( ingestion_manager, expiration_manager) emission_manager.set_ingestion_manager_and_expiration_manager( ingestion_manager, expiration_manager) ingestion_manager.set_expiration_manager(expiration_manager) transmission_manager.inmit(payload, complete) if subscription.kind is interfaces.ServicedSubscription.Kind.NONE: returned_reception_manager = None else: returned_reception_manager = reception_manager return _FrontManagement( returned_reception_manager, emission_manager, operation_context, cancellation_manager) class FrontLink(interfaces.FrontLink): """An implementation of interfaces.FrontLink.""" def __init__(self, work_pool, transmission_pool, utility_pool): """Constructor. Args: work_pool: A thread pool to be used for executing customer code. transmission_pool: A thread pool to be used for transmitting values to the other side of the operation. utility_pool: A thread pool to be used for utility tasks. """ self._endlette = _Endlette(utility_pool) self._work_pool = work_pool self._transmission_pool = transmission_pool self._utility_pool = utility_pool self._callback = None self._operations = {} def join_rear_link(self, rear_link): """See interfaces.ForeLink.join_rear_link for specification.""" with self._endlette: self._callback = rear_link.accept_front_to_back_ticket def operation_stats(self): """See interfaces.End.operation_stats for specification.""" return self._endlette.operation_stats() def add_idle_action(self, action): """See interfaces.End.add_idle_action for specification.""" self._endlette.add_idle_action(action) def operate( self, name, payload, complete, timeout, subscription, trace_id): """See interfaces.Front.operate for specification.""" operation_id = uuid.uuid4() with self._endlette: management = _front_operate( self._callback, self._work_pool, self._transmission_pool, self._utility_pool, self._endlette.terminal_action(operation_id), operation_id, name, payload, complete, timeout, subscription, trace_id) self._endlette.add_operation(operation_id, management.reception) return _EasyOperation( management.emission, management.operation, management.cancellation) def accept_back_to_front_ticket(self, ticket): """See interfaces.End.act for specification.""" with self._endlette: reception_manager = self._endlette.get_operation(ticket.operation_id) if reception_manager: reception_manager.receive_ticket(ticket) def _back_operate( servicer, callback, work_pool, transmission_pool, utility_pool, termination_action, ticket, default_timeout, maximum_timeout): """Constructs objects necessary for back-side operation management. Also begins back-side operation by feeding the first received ticket into the constructed _interfaces.ReceptionManager. Args: servicer: An interfaces.Servicer for servicing operations. callback: A callable that accepts interfaces.BackToFrontTickets and delivers them to the other side of the operation. Execution of this callable may take any arbitrary length of time. work_pool: A thread pool in which to execute customer code. transmission_pool: A thread pool to use for transmitting to the other side of the operation. utility_pool: A thread pool for utility tasks. termination_action: A no-arg behavior to be called upon operation completion. ticket: The first interfaces.FrontToBackTicket received for the operation. default_timeout: A length of time in seconds to be used as the default time alloted for a single operation. maximum_timeout: A length of time in seconds to be used as the maximum time alloted for a single operation. Returns: The _interfaces.ReceptionManager to be used for the operation. """ lock = threading.Lock() with lock: termination_manager = _termination.back_termination_manager( work_pool, utility_pool, termination_action, ticket.subscription) transmission_manager = _transmission.back_transmission_manager( lock, transmission_pool, callback, ticket.operation_id, termination_manager, ticket.subscription) operation_context = _context.OperationContext( lock, ticket.operation_id, interfaces.Outcome.SERVICER_FAILURE, termination_manager, transmission_manager) emission_manager = _emission.back_emission_manager( lock, termination_manager, transmission_manager) ingestion_manager = _ingestion.back_ingestion_manager( lock, work_pool, servicer, termination_manager, transmission_manager, operation_context, emission_manager) expiration_manager = _expiration.back_expiration_manager( lock, termination_manager, transmission_manager, ingestion_manager, ticket.timeout, default_timeout, maximum_timeout) reception_manager = _reception.back_reception_manager( lock, termination_manager, transmission_manager, ingestion_manager, expiration_manager) termination_manager.set_expiration_manager(expiration_manager) transmission_manager.set_ingestion_and_expiration_managers( ingestion_manager, expiration_manager) operation_context.set_ingestion_and_expiration_managers( ingestion_manager, expiration_manager) emission_manager.set_ingestion_manager_and_expiration_manager( ingestion_manager, expiration_manager) ingestion_manager.set_expiration_manager(expiration_manager) reception_manager.receive_ticket(ticket) return reception_manager class BackLink(interfaces.BackLink): """An implementation of interfaces.BackLink.""" def __init__( self, servicer, work_pool, transmission_pool, utility_pool, default_timeout, maximum_timeout): """Constructor. Args: servicer: An interfaces.Servicer for servicing operations. work_pool: A thread pool in which to execute customer code. transmission_pool: A thread pool to use for transmitting to the other side of the operation. utility_pool: A thread pool for utility tasks. default_timeout: A length of time in seconds to be used as the default time alloted for a single operation. maximum_timeout: A length of time in seconds to be used as the maximum time alloted for a single operation. """ self._endlette = _Endlette(utility_pool) self._servicer = servicer self._work_pool = work_pool self._transmission_pool = transmission_pool self._utility_pool = utility_pool self._default_timeout = default_timeout self._maximum_timeout = maximum_timeout self._callback = None def join_fore_link(self, fore_link): """See interfaces.RearLink.join_fore_link for specification.""" with self._endlette: self._callback = fore_link.accept_back_to_front_ticket def accept_front_to_back_ticket(self, ticket): """See interfaces.RearLink.accept_front_to_back_ticket for specification.""" with self._endlette: reception_manager = self._endlette.get_operation(ticket.operation_id) if reception_manager is None: reception_manager = _back_operate( self._servicer, self._callback, self._work_pool, self._transmission_pool, self._utility_pool, self._endlette.terminal_action(ticket.operation_id), ticket, self._default_timeout, self._maximum_timeout) self._endlette.add_operation(ticket.operation_id, reception_manager) else: reception_manager.receive_ticket(ticket) def operation_stats(self): """See interfaces.End.operation_stats for specification.""" return self._endlette.operation_stats() def add_idle_action(self, action): """See interfaces.End.add_idle_action for specification.""" self._endlette.add_idle_action(action) grpc-0.11.1/src/python/grpcio/grpc/framework/base/_cancellation.py0000644000175000017500000000547412600663151025333 0ustar apollockapollock# 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. """State and behavior for operation cancellation.""" from grpc.framework.base import _interfaces from grpc.framework.base import interfaces class CancellationManager(_interfaces.CancellationManager): """An implementation of _interfaces.CancellationManager.""" def __init__( self, lock, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Constructor. Args: lock: The operation-wide lock. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. ingestion_manager: The _interfaces.IngestionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ self._lock = lock self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._ingestion_manager = ingestion_manager self._expiration_manager = expiration_manager def cancel(self): """See _interfaces.CancellationManager.cancel for specification.""" with self._lock: self._termination_manager.abort(interfaces.Outcome.CANCELLED) self._transmission_manager.abort(interfaces.Outcome.CANCELLED) self._ingestion_manager.abort() self._expiration_manager.abort() grpc-0.11.1/src/python/grpcio/grpc/framework/base/_reception.py0000644000175000017500000003457712600663151024675 0ustar apollockapollock# 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. """State and behavior for ticket reception.""" import abc from grpc.framework.base import interfaces from grpc.framework.base import _interfaces _INITIAL_FRONT_TO_BACK_TICKET_KINDS = ( interfaces.FrontToBackTicket.Kind.COMMENCEMENT, interfaces.FrontToBackTicket.Kind.ENTIRE, ) class _Receiver(object): """Common specification of different ticket-handling behavior.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def abort_if_abortive(self, ticket): """Aborts the operation if the ticket is abortive. Args: ticket: A just-arrived ticket. Returns: A boolean indicating whether or not this Receiver aborted the operation based on the ticket. """ raise NotImplementedError() @abc.abstractmethod def receive(self, ticket): """Handles a just-arrived ticket. Args: ticket: A just-arrived ticket. Returns: A boolean indicating whether or not the ticket was terminal (i.e. whether or not non-abortive tickets are legal after this one). """ raise NotImplementedError() @abc.abstractmethod def reception_failure(self): """Aborts the operation with an indication of reception failure.""" raise NotImplementedError() def _abort( outcome, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Indicates abortion with the given outcome to the given managers.""" termination_manager.abort(outcome) transmission_manager.abort(outcome) ingestion_manager.abort() expiration_manager.abort() def _abort_if_abortive( ticket, abortive, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Determines a ticket's being abortive and if so aborts the operation. Args: ticket: A just-arrived ticket. abortive: A callable that takes a ticket and returns an interfaces.Outcome indicating that the operation should be aborted or None indicating that the operation should not be aborted. termination_manager: The operation's _interfaces.TerminationManager. transmission_manager: The operation's _interfaces.TransmissionManager. ingestion_manager: The operation's _interfaces.IngestionManager. expiration_manager: The operation's _interfaces.ExpirationManager. Returns: True if the operation was aborted; False otherwise. """ abortion_outcome = abortive(ticket) if abortion_outcome is None: return False else: _abort( abortion_outcome, termination_manager, transmission_manager, ingestion_manager, expiration_manager) return True def _reception_failure( termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Aborts the operation with an indication of reception failure.""" _abort( interfaces.Outcome.RECEPTION_FAILURE, termination_manager, transmission_manager, ingestion_manager, expiration_manager) class _BackReceiver(_Receiver): """Ticket-handling specific to the back side of an operation.""" def __init__( self, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Constructor. Args: termination_manager: The operation's _interfaces.TerminationManager. transmission_manager: The operation's _interfaces.TransmissionManager. ingestion_manager: The operation's _interfaces.IngestionManager. expiration_manager: The operation's _interfaces.ExpirationManager. """ self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._ingestion_manager = ingestion_manager self._expiration_manager = expiration_manager self._first_ticket_seen = False self._last_ticket_seen = False def _abortive(self, ticket): """Determines whether or not (and if so, how) a ticket is abortive. Args: ticket: A just-arrived ticket. Returns: An interfaces.Outcome value describing operation abortion if the ticket is abortive or None if the ticket is not abortive. """ if ticket.kind is interfaces.FrontToBackTicket.Kind.CANCELLATION: return interfaces.Outcome.CANCELLED elif ticket.kind is interfaces.FrontToBackTicket.Kind.EXPIRATION: return interfaces.Outcome.EXPIRED elif ticket.kind is interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE: return interfaces.Outcome.SERVICED_FAILURE elif ticket.kind is interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE: return interfaces.Outcome.SERVICED_FAILURE elif (ticket.kind in _INITIAL_FRONT_TO_BACK_TICKET_KINDS and self._first_ticket_seen): return interfaces.Outcome.RECEPTION_FAILURE elif self._last_ticket_seen: return interfaces.Outcome.RECEPTION_FAILURE else: return None def abort_if_abortive(self, ticket): """See _Receiver.abort_if_abortive for specification.""" return _abort_if_abortive( ticket, self._abortive, self._termination_manager, self._transmission_manager, self._ingestion_manager, self._expiration_manager) def receive(self, ticket): """See _Receiver.receive for specification.""" if ticket.timeout is not None: self._expiration_manager.change_timeout(ticket.timeout) if ticket.kind is interfaces.FrontToBackTicket.Kind.COMMENCEMENT: self._first_ticket_seen = True self._ingestion_manager.start(ticket.name) if ticket.payload is not None: self._ingestion_manager.consume(ticket.payload) elif ticket.kind is interfaces.FrontToBackTicket.Kind.CONTINUATION: self._ingestion_manager.consume(ticket.payload) elif ticket.kind is interfaces.FrontToBackTicket.Kind.COMPLETION: self._last_ticket_seen = True if ticket.payload is None: self._ingestion_manager.terminate() else: self._ingestion_manager.consume_and_terminate(ticket.payload) else: self._first_ticket_seen = True self._last_ticket_seen = True self._ingestion_manager.start(ticket.name) if ticket.payload is None: self._ingestion_manager.terminate() else: self._ingestion_manager.consume_and_terminate(ticket.payload) def reception_failure(self): """See _Receiver.reception_failure for specification.""" _reception_failure( self._termination_manager, self._transmission_manager, self._ingestion_manager, self._expiration_manager) class _FrontReceiver(_Receiver): """Ticket-handling specific to the front side of an operation.""" def __init__( self, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Constructor. Args: termination_manager: The operation's _interfaces.TerminationManager. transmission_manager: The operation's _interfaces.TransmissionManager. ingestion_manager: The operation's _interfaces.IngestionManager. expiration_manager: The operation's _interfaces.ExpirationManager. """ self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._ingestion_manager = ingestion_manager self._expiration_manager = expiration_manager self._last_ticket_seen = False def _abortive(self, ticket): """Determines whether or not (and if so, how) a ticket is abortive. Args: ticket: A just-arrived ticket. Returns: An interfaces.Outcome value describing operation abortion if the ticket is abortive or None if the ticket is not abortive. """ if ticket.kind is interfaces.BackToFrontTicket.Kind.CANCELLATION: return interfaces.Outcome.CANCELLED elif ticket.kind is interfaces.BackToFrontTicket.Kind.EXPIRATION: return interfaces.Outcome.EXPIRED elif ticket.kind is interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE: return interfaces.Outcome.SERVICER_FAILURE elif ticket.kind is interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE: return interfaces.Outcome.SERVICER_FAILURE elif self._last_ticket_seen: return interfaces.Outcome.RECEPTION_FAILURE else: return None def abort_if_abortive(self, ticket): """See _Receiver.abort_if_abortive for specification.""" return _abort_if_abortive( ticket, self._abortive, self._termination_manager, self._transmission_manager, self._ingestion_manager, self._expiration_manager) def receive(self, ticket): """See _Receiver.receive for specification.""" if ticket.kind is interfaces.BackToFrontTicket.Kind.CONTINUATION: self._ingestion_manager.consume(ticket.payload) elif ticket.kind is interfaces.BackToFrontTicket.Kind.COMPLETION: self._last_ticket_seen = True if ticket.payload is None: self._ingestion_manager.terminate() else: self._ingestion_manager.consume_and_terminate(ticket.payload) def reception_failure(self): """See _Receiver.reception_failure for specification.""" _reception_failure( self._termination_manager, self._transmission_manager, self._ingestion_manager, self._expiration_manager) class _ReceptionManager(_interfaces.ReceptionManager): """A ReceptionManager based around a _Receiver passed to it.""" def __init__(self, lock, receiver): """Constructor. Args: lock: The operation-servicing-wide lock object. receiver: A _Receiver responsible for handling received tickets. """ self._lock = lock self._receiver = receiver self._lowest_unseen_sequence_number = 0 self._out_of_sequence_tickets = {} self._completed_sequence_number = None self._aborted = False def _sequence_failure(self, ticket): """Determines a just-arrived ticket's sequential legitimacy. Args: ticket: A just-arrived ticket. Returns: True if the ticket is sequentially legitimate; False otherwise. """ if ticket.sequence_number < self._lowest_unseen_sequence_number: return True elif ticket.sequence_number in self._out_of_sequence_tickets: return True elif (self._completed_sequence_number is not None and self._completed_sequence_number <= ticket.sequence_number): return True else: return False def _process(self, ticket): """Process those tickets ready to be processed. Args: ticket: A just-arrived ticket the sequence number of which matches this _ReceptionManager's _lowest_unseen_sequence_number field. """ while True: completed = self._receiver.receive(ticket) if completed: self._out_of_sequence_tickets.clear() self._completed_sequence_number = ticket.sequence_number self._lowest_unseen_sequence_number = ticket.sequence_number + 1 return else: next_ticket = self._out_of_sequence_tickets.pop( ticket.sequence_number + 1, None) if next_ticket is None: self._lowest_unseen_sequence_number = ticket.sequence_number + 1 return else: ticket = next_ticket def receive_ticket(self, ticket): """See _interfaces.ReceptionManager.receive_ticket for specification.""" with self._lock: if self._aborted: return elif self._sequence_failure(ticket): self._receiver.reception_failure() self._aborted = True elif self._receiver.abort_if_abortive(ticket): self._aborted = True elif ticket.sequence_number == self._lowest_unseen_sequence_number: self._process(ticket) else: self._out_of_sequence_tickets[ticket.sequence_number] = ticket def front_reception_manager( lock, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Creates a _interfaces.ReceptionManager for front-side use. Args: lock: The operation-servicing-wide lock object. termination_manager: The operation's _interfaces.TerminationManager. transmission_manager: The operation's _interfaces.TransmissionManager. ingestion_manager: The operation's _interfaces.IngestionManager. expiration_manager: The operation's _interfaces.ExpirationManager. Returns: A _interfaces.ReceptionManager appropriate for front-side use. """ return _ReceptionManager( lock, _FrontReceiver( termination_manager, transmission_manager, ingestion_manager, expiration_manager)) def back_reception_manager( lock, termination_manager, transmission_manager, ingestion_manager, expiration_manager): """Creates a _interfaces.ReceptionManager for back-side use. Args: lock: The operation-servicing-wide lock object. termination_manager: The operation's _interfaces.TerminationManager. transmission_manager: The operation's _interfaces.TransmissionManager. ingestion_manager: The operation's _interfaces.IngestionManager. expiration_manager: The operation's _interfaces.ExpirationManager. Returns: A _interfaces.ReceptionManager appropriate for back-side use. """ return _ReceptionManager( lock, _BackReceiver( termination_manager, transmission_manager, ingestion_manager, expiration_manager)) grpc-0.11.1/src/python/grpcio/grpc/framework/base/in_memory.py0000644000175000017500000000773412600663151024537 0ustar apollockapollock# 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. """In-memory implementations of base layer interfaces.""" import threading from grpc.framework.base import _constants from grpc.framework.base import interfaces from grpc.framework.foundation import callable_util class _Serializer(object): """A utility for serializing values that may arrive concurrently.""" def __init__(self, pool): self._lock = threading.Lock() self._pool = pool self._sink = None self._spinning = False self._values = [] def _spin(self, sink, value): while True: sink(value) with self._lock: if self._sink is None or not self._values: self._spinning = False return else: sink, value = self._sink, self._values.pop(0) def set_sink(self, sink): with self._lock: self._sink = sink if sink is not None and self._values and not self._spinning: self._spinning = True self._pool.submit( callable_util.with_exceptions_logged( self._spin, _constants.INTERNAL_ERROR_LOG_MESSAGE), sink, self._values.pop(0)) def add_value(self, value): with self._lock: if self._sink and not self._spinning: self._spinning = True self._pool.submit( callable_util.with_exceptions_logged( self._spin, _constants.INTERNAL_ERROR_LOG_MESSAGE), self._sink, value) else: self._values.append(value) class Link(interfaces.ForeLink, interfaces.RearLink): """A trivial implementation of interfaces.ForeLink and interfaces.RearLink.""" def __init__(self, pool): """Constructor. Args: pool: A thread pool to be used for serializing ticket exchange in each direction. """ self._front_to_back = _Serializer(pool) self._back_to_front = _Serializer(pool) def join_fore_link(self, fore_link): """See interfaces.RearLink.join_fore_link for specification.""" self._back_to_front.set_sink(fore_link.accept_back_to_front_ticket) def join_rear_link(self, rear_link): """See interfaces.ForeLink.join_rear_link for specification.""" self._front_to_back.set_sink(rear_link.accept_front_to_back_ticket) def accept_front_to_back_ticket(self, ticket): """See interfaces.ForeLink.accept_front_to_back_ticket for specification.""" self._front_to_back.add_value(ticket) def accept_back_to_front_ticket(self, ticket): """See interfaces.RearLink.accept_back_to_front_ticket for specification.""" self._back_to_front.add_value(ticket) grpc-0.11.1/src/python/grpcio/grpc/framework/base/_context.py0000644000175000017500000000776712600663151024372 0ustar apollockapollock# 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. """State and behavior for operation context.""" import time # _interfaces is referenced from specification in this module. from grpc.framework.base import interfaces from grpc.framework.base import _interfaces # pylint: disable=unused-import class OperationContext(interfaces.OperationContext): """An implementation of interfaces.OperationContext.""" def __init__( self, lock, operation_id, local_failure, termination_manager, transmission_manager): """Constructor. Args: lock: The operation-wide lock. operation_id: An object identifying the operation. local_failure: Whichever one of interfaces.Outcome.SERVICED_FAILURE or interfaces.Outcome.SERVICER_FAILURE describes local failure of customer code. termination_manager: The _interfaces.TerminationManager for the operation. transmission_manager: The _interfaces.TransmissionManager for the operation. """ self._lock = lock self._local_failure = local_failure self._termination_manager = termination_manager self._transmission_manager = transmission_manager self._ingestion_manager = None self._expiration_manager = None self.operation_id = operation_id def set_ingestion_and_expiration_managers( self, ingestion_manager, expiration_manager): """Sets managers with which this OperationContext cooperates. Args: ingestion_manager: The _interfaces.IngestionManager for the operation. expiration_manager: The _interfaces.ExpirationManager for the operation. """ self._ingestion_manager = ingestion_manager self._expiration_manager = expiration_manager def is_active(self): """See interfaces.OperationContext.is_active for specification.""" with self._lock: return self._termination_manager.is_active() def add_termination_callback(self, callback): """See interfaces.OperationContext.add_termination_callback.""" with self._lock: self._termination_manager.add_callback(callback) def time_remaining(self): """See interfaces.OperationContext.time_remaining for specification.""" with self._lock: deadline = self._expiration_manager.deadline() return max(0.0, deadline - time.time()) def fail(self, exception): """See interfaces.OperationContext.fail for specification.""" with self._lock: self._termination_manager.abort(self._local_failure) self._transmission_manager.abort(self._local_failure) self._ingestion_manager.abort() self._expiration_manager.abort() grpc-0.11.1/src/python/grpcio/grpc/framework/base/_interfaces.py0000644000175000017500000002100312600663151025004 0ustar apollockapollock# 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. """Package-internal interfaces.""" import abc # interfaces is referenced from specification in this module. from grpc.framework.base import interfaces # pylint: disable=unused-import from grpc.framework.foundation import stream class TerminationManager(object): """An object responsible for handling the termination of an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_expiration_manager(self, expiration_manager): """Sets the ExpirationManager with which this object will cooperate.""" raise NotImplementedError() @abc.abstractmethod def is_active(self): """Reports whether or not the operation is active. Returns: True if the operation is active or False if the operation has terminated. """ raise NotImplementedError() @abc.abstractmethod def add_callback(self, callback): """Registers a callback to be called on operation termination. If the operation has already terminated, the callback will be called immediately. Args: callback: A callable that will be passed an interfaces.Outcome value. """ raise NotImplementedError() @abc.abstractmethod def emission_complete(self): """Indicates that emissions from customer code have completed.""" raise NotImplementedError() @abc.abstractmethod def transmission_complete(self): """Indicates that transmissions to the remote end are complete.""" raise NotImplementedError() @abc.abstractmethod def ingestion_complete(self): """Indicates that customer code ingestion of received values is complete.""" raise NotImplementedError() @abc.abstractmethod def abort(self, outcome): """Indicates that the operation must abort for the indicated reason. Args: outcome: An interfaces.Outcome indicating operation abortion. """ raise NotImplementedError() class TransmissionManager(object): """A manager responsible for transmitting to the other end of an operation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def inmit(self, emission, complete): """Accepts a value for transmission to the other end of the operation. Args: emission: A value of some significance to the customer to be transmitted to the other end of the operation. May be None only if complete is True. complete: A boolean that if True indicates that customer code has emitted all values it intends to emit. """ raise NotImplementedError() @abc.abstractmethod def abort(self, outcome): """Indicates that the operation has aborted for the indicated reason. Args: outcome: An interfaces.Outcome indicating operation abortion. """ raise NotImplementedError() class EmissionManager(stream.Consumer): """A manager of values emitted by customer code.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_ingestion_manager_and_expiration_manager( self, ingestion_manager, expiration_manager): """Sets two other objects with which this EmissionManager will cooperate. Args: ingestion_manager: The IngestionManager for the operation. expiration_manager: The ExpirationManager for the operation. """ raise NotImplementedError() @abc.abstractmethod def consume(self, value): """Accepts a value emitted by customer code. This method should only be called by customer code. Args: value: Any value of significance to the customer. """ raise NotImplementedError() @abc.abstractmethod def terminate(self): """Indicates that no more values will be emitted by customer code. This method should only be called by customer code. Implementations of this method may be idempotent and forgive customer code calling this method more than once. """ raise NotImplementedError() @abc.abstractmethod def consume_and_terminate(self, value): """Accepts the last value emitted by customer code. This method should only be called by customer code. Args: value: Any value of significance to the customer. """ raise NotImplementedError() class IngestionManager(stream.Consumer): """A manager responsible for executing customer code.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_expiration_manager(self, expiration_manager): """Sets the ExpirationManager with which this object will cooperate.""" raise NotImplementedError() @abc.abstractmethod def start(self, requirement): """Commences execution of customer code. Args: requirement: Some value unavailable at the time of this object's construction that is required to begin executing customer code. """ raise NotImplementedError() @abc.abstractmethod def consume(self, payload): """Accepts a customer-significant value to be supplied to customer code. Args: payload: Some customer-significant value. """ raise NotImplementedError() @abc.abstractmethod def terminate(self): """Indicates the end of values to be supplied to customer code.""" raise NotImplementedError() @abc.abstractmethod def consume_and_terminate(self, payload): """Accepts the last value to be supplied to customer code. Args: payload: Some customer-significant value (and the last such value). """ raise NotImplementedError() @abc.abstractmethod def abort(self): """Indicates to this manager that the operation has aborted.""" raise NotImplementedError() class ExpirationManager(object): """A manager responsible for aborting the operation if it runs out of time.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def change_timeout(self, timeout): """Changes the timeout allotted for the operation. Operation duration is always measure from the beginning of the operation; calling this method changes the operation's allotted time to timeout total seconds, not timeout seconds from the time of this method call. Args: timeout: A length of time in seconds to allow for the operation. """ raise NotImplementedError() @abc.abstractmethod def deadline(self): """Returns the time until which the operation is allowed to run. Returns: The time (seconds since the epoch) at which the operation will expire. """ raise NotImplementedError() @abc.abstractmethod def abort(self): """Indicates to this manager that the operation has aborted.""" raise NotImplementedError() class ReceptionManager(object): """A manager responsible for receiving tickets from the other end.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def receive_ticket(self, ticket): """Handle a ticket from the other side of the operation. Args: ticket: An interfaces.BackToFrontTicket or interfaces.FrontToBackTicket appropriate to this end of the operation and this object. """ raise NotImplementedError() class CancellationManager(object): """A manager of operation cancellation.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def cancel(self): """Cancels the operation.""" raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/framework/base/_transmission.py0000644000175000017500000004020612600663151025420 0ustar apollockapollock# 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. """State and behavior for ticket transmission during an operation.""" import abc from grpc.framework.base import _constants from grpc.framework.base import _interfaces from grpc.framework.base import interfaces from grpc.framework.foundation import callable_util _TRANSMISSION_EXCEPTION_LOG_MESSAGE = 'Exception during transmission!' _FRONT_TO_BACK_NO_TRANSMISSION_OUTCOMES = ( interfaces.Outcome.SERVICER_FAILURE, ) _BACK_TO_FRONT_NO_TRANSMISSION_OUTCOMES = ( interfaces.Outcome.CANCELLED, interfaces.Outcome.SERVICED_FAILURE, ) _ABORTION_OUTCOME_TO_FRONT_TO_BACK_TICKET_KIND = { interfaces.Outcome.CANCELLED: interfaces.FrontToBackTicket.Kind.CANCELLATION, interfaces.Outcome.EXPIRED: interfaces.FrontToBackTicket.Kind.EXPIRATION, interfaces.Outcome.RECEPTION_FAILURE: interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE, interfaces.Outcome.TRANSMISSION_FAILURE: interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, interfaces.Outcome.SERVICED_FAILURE: interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE, interfaces.Outcome.SERVICER_FAILURE: interfaces.FrontToBackTicket.Kind.SERVICER_FAILURE, } _ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND = { interfaces.Outcome.CANCELLED: interfaces.BackToFrontTicket.Kind.CANCELLATION, interfaces.Outcome.EXPIRED: interfaces.BackToFrontTicket.Kind.EXPIRATION, interfaces.Outcome.RECEPTION_FAILURE: interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE, interfaces.Outcome.TRANSMISSION_FAILURE: interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, interfaces.Outcome.SERVICED_FAILURE: interfaces.BackToFrontTicket.Kind.SERVICED_FAILURE, interfaces.Outcome.SERVICER_FAILURE: interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE, } class _Ticketizer(object): """Common specification of different ticket-creating behavior.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def ticketize(self, operation_id, sequence_number, payload, complete): """Creates a ticket indicating ordinary operation progress. Args: operation_id: The operation ID for the current operation. sequence_number: A sequence number for the ticket. payload: A customer payload object. May be None if sequence_number is zero or complete is true. complete: A boolean indicating whether or not the ticket should describe itself as (but for a later indication of operation abortion) the last ticket to be sent. Returns: An object of an appropriate type suitable for transmission to the other side of the operation. """ raise NotImplementedError() @abc.abstractmethod def ticketize_abortion(self, operation_id, sequence_number, outcome): """Creates a ticket indicating that the operation is aborted. Args: operation_id: The operation ID for the current operation. sequence_number: A sequence number for the ticket. outcome: An interfaces.Outcome value describing the operation abortion. Returns: An object of an appropriate type suitable for transmission to the other side of the operation, or None if transmission is not appropriate for the given outcome. """ raise NotImplementedError() class _FrontTicketizer(_Ticketizer): """Front-side ticket-creating behavior.""" def __init__(self, name, subscription_kind, trace_id, timeout): """Constructor. Args: name: The name of the operation. subscription_kind: An interfaces.ServicedSubscription.Kind value describing the interest the front has in tickets sent from the back. trace_id: A uuid.UUID identifying a set of related operations to which this operation belongs. timeout: A length of time in seconds to allow for the entire operation. """ self._name = name self._subscription_kind = subscription_kind self._trace_id = trace_id self._timeout = timeout def ticketize(self, operation_id, sequence_number, payload, complete): """See _Ticketizer.ticketize for specification.""" if sequence_number: if complete: kind = interfaces.FrontToBackTicket.Kind.COMPLETION else: kind = interfaces.FrontToBackTicket.Kind.CONTINUATION return interfaces.FrontToBackTicket( operation_id, sequence_number, kind, self._name, self._subscription_kind, self._trace_id, payload, self._timeout) else: if complete: kind = interfaces.FrontToBackTicket.Kind.ENTIRE else: kind = interfaces.FrontToBackTicket.Kind.COMMENCEMENT return interfaces.FrontToBackTicket( operation_id, 0, kind, self._name, self._subscription_kind, self._trace_id, payload, self._timeout) def ticketize_abortion(self, operation_id, sequence_number, outcome): """See _Ticketizer.ticketize_abortion for specification.""" if outcome in _FRONT_TO_BACK_NO_TRANSMISSION_OUTCOMES: return None else: kind = _ABORTION_OUTCOME_TO_FRONT_TO_BACK_TICKET_KIND[outcome] return interfaces.FrontToBackTicket( operation_id, sequence_number, kind, None, None, None, None, None) class _BackTicketizer(_Ticketizer): """Back-side ticket-creating behavior.""" def ticketize(self, operation_id, sequence_number, payload, complete): """See _Ticketizer.ticketize for specification.""" if complete: kind = interfaces.BackToFrontTicket.Kind.COMPLETION else: kind = interfaces.BackToFrontTicket.Kind.CONTINUATION return interfaces.BackToFrontTicket( operation_id, sequence_number, kind, payload) def ticketize_abortion(self, operation_id, sequence_number, outcome): """See _Ticketizer.ticketize_abortion for specification.""" if outcome in _BACK_TO_FRONT_NO_TRANSMISSION_OUTCOMES: return None else: kind = _ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND[outcome] return interfaces.BackToFrontTicket( operation_id, sequence_number, kind, None) class TransmissionManager(_interfaces.TransmissionManager): """A _interfaces.TransmissionManager on which other managers may be set.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_ingestion_and_expiration_managers( self, ingestion_manager, expiration_manager): """Sets two of the other managers with which this manager may interact. Args: ingestion_manager: The _interfaces.IngestionManager associated with the current operation. expiration_manager: The _interfaces.ExpirationManager associated with the current operation. """ raise NotImplementedError() class _EmptyTransmissionManager(TransmissionManager): """A completely no-operative _interfaces.TransmissionManager.""" def set_ingestion_and_expiration_managers( self, ingestion_manager, expiration_manager): """See overriden method for specification.""" def inmit(self, emission, complete): """See _interfaces.TransmissionManager.inmit for specification.""" def abort(self, outcome): """See _interfaces.TransmissionManager.abort for specification.""" class _TransmittingTransmissionManager(TransmissionManager): """A TransmissionManager implementation that sends tickets.""" def __init__( self, lock, pool, callback, operation_id, ticketizer, termination_manager): """Constructor. Args: lock: The operation-servicing-wide lock object. pool: A thread pool in which the work of transmitting tickets will be performed. callback: A callable that accepts tickets and sends them to the other side of the operation. operation_id: The operation's ID. ticketizer: A _Ticketizer for ticket creation. termination_manager: The _interfaces.TerminationManager associated with this operation. """ self._lock = lock self._pool = pool self._callback = callback self._operation_id = operation_id self._ticketizer = ticketizer self._termination_manager = termination_manager self._ingestion_manager = None self._expiration_manager = None self._emissions = [] self._emission_complete = False self._outcome = None self._lowest_unused_sequence_number = 0 self._transmitting = False def set_ingestion_and_expiration_managers( self, ingestion_manager, expiration_manager): """See overridden method for specification.""" self._ingestion_manager = ingestion_manager self._expiration_manager = expiration_manager def _lead_ticket(self, emission, complete): """Creates a ticket suitable for leading off the transmission loop. Args: emission: A customer payload object to be sent to the other side of the operation. complete: Whether or not the sequence of customer payloads ends with the passed object. Returns: A ticket with which to lead off the transmission loop. """ sequence_number = self._lowest_unused_sequence_number self._lowest_unused_sequence_number += 1 return self._ticketizer.ticketize( self._operation_id, sequence_number, emission, complete) def _abortive_response_ticket(self, outcome): """Creates a ticket indicating operation abortion. Args: outcome: An interfaces.Outcome value describing operation abortion. Returns: A ticket indicating operation abortion. """ ticket = self._ticketizer.ticketize_abortion( self._operation_id, self._lowest_unused_sequence_number, outcome) if ticket is None: return None else: self._lowest_unused_sequence_number += 1 return ticket def _next_ticket(self): """Creates the next ticket to be sent to the other side of the operation. Returns: A (completed, ticket) tuple comprised of a boolean indicating whether or not the sequence of tickets has completed normally and a ticket to send to the other side if the sequence of tickets hasn't completed. The tuple will never have both a True first element and a non-None second element. """ if self._emissions is None: return False, None elif self._outcome is None: if self._emissions: payload = self._emissions.pop(0) complete = self._emission_complete and not self._emissions sequence_number = self._lowest_unused_sequence_number self._lowest_unused_sequence_number += 1 return complete, self._ticketizer.ticketize( self._operation_id, sequence_number, payload, complete) else: return self._emission_complete, None else: ticket = self._abortive_response_ticket(self._outcome) self._emissions = None return False, None if ticket is None else ticket def _transmit(self, ticket): """Commences the transmission loop sending tickets. Args: ticket: A ticket to be sent to the other side of the operation. """ def transmit(ticket): while True: transmission_outcome = callable_util.call_logging_exceptions( self._callback, _TRANSMISSION_EXCEPTION_LOG_MESSAGE, ticket) if transmission_outcome.exception is None: with self._lock: complete, ticket = self._next_ticket() if ticket is None: if complete: self._termination_manager.transmission_complete() self._transmitting = False return else: with self._lock: self._emissions = None self._termination_manager.abort( interfaces.Outcome.TRANSMISSION_FAILURE) self._ingestion_manager.abort() self._expiration_manager.abort() self._transmitting = False return self._pool.submit(callable_util.with_exceptions_logged( transmit, _constants.INTERNAL_ERROR_LOG_MESSAGE), ticket) self._transmitting = True def inmit(self, emission, complete): """See _interfaces.TransmissionManager.inmit for specification.""" if self._emissions is not None and self._outcome is None: self._emission_complete = complete if self._transmitting: self._emissions.append(emission) else: self._transmit(self._lead_ticket(emission, complete)) def abort(self, outcome): """See _interfaces.TransmissionManager.abort for specification.""" if self._emissions is not None and self._outcome is None: self._outcome = outcome if not self._transmitting: ticket = self._abortive_response_ticket(outcome) self._emissions = None if ticket is not None: self._transmit(ticket) def front_transmission_manager( lock, pool, callback, operation_id, name, subscription_kind, trace_id, timeout, termination_manager): """Creates a TransmissionManager appropriate for front-side use. Args: lock: The operation-servicing-wide lock object. pool: A thread pool in which the work of transmitting tickets will be performed. callback: A callable that accepts tickets and sends them to the other side of the operation. operation_id: The operation's ID. name: The name of the operation. subscription_kind: An interfaces.ServicedSubscription.Kind value describing the interest the front has in tickets sent from the back. trace_id: A uuid.UUID identifying a set of related operations to which this operation belongs. timeout: A length of time in seconds to allow for the entire operation. termination_manager: The _interfaces.TerminationManager associated with this operation. Returns: A TransmissionManager appropriate for front-side use. """ return _TransmittingTransmissionManager( lock, pool, callback, operation_id, _FrontTicketizer( name, subscription_kind, trace_id, timeout), termination_manager) def back_transmission_manager( lock, pool, callback, operation_id, termination_manager, subscription_kind): """Creates a TransmissionManager appropriate for back-side use. Args: lock: The operation-servicing-wide lock object. pool: A thread pool in which the work of transmitting tickets will be performed. callback: A callable that accepts tickets and sends them to the other side of the operation. operation_id: The operation's ID. termination_manager: The _interfaces.TerminationManager associated with this operation. subscription_kind: An interfaces.ServicedSubscription.Kind value describing the interest the front has in tickets sent from the back. Returns: A TransmissionManager appropriate for back-side use. """ if subscription_kind is interfaces.ServicedSubscription.Kind.NONE: return _EmptyTransmissionManager() else: return _TransmittingTransmissionManager( lock, pool, callback, operation_id, _BackTicketizer(), termination_manager) grpc-0.11.1/src/python/grpcio/grpc/_links/0000755000175000017500000000000012600663151020524 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_links/_constants.py0000644000175000017500000000361012600663151023251 0ustar apollockapollock# 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. """Constants for use within this package.""" from grpc._adapter import _intermediary_low from grpc.beta import interfaces as beta_interfaces LOW_STATUS_CODE_TO_HIGH_STATUS_CODE = { low: high for low, high in zip( _intermediary_low.Code, beta_interfaces.StatusCode) } HIGH_STATUS_CODE_TO_LOW_STATUS_CODE = { high: low for low, high in LOW_STATUS_CODE_TO_HIGH_STATUS_CODE.items() } grpc-0.11.1/src/python/grpcio/grpc/_links/invocation.py0000644000175000017500000004041412600663151023252 0ustar apollockapollock# 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. """The RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire.""" import abc import enum import logging import threading import time from grpc._adapter import _intermediary_low from grpc._links import _constants from grpc.beta import interfaces as beta_interfaces from grpc.framework.foundation import activated from grpc.framework.foundation import logging_pool from grpc.framework.foundation import relay from grpc.framework.interfaces.links import links _IDENTITY = lambda x: x _STOP = _intermediary_low.Event.Kind.STOP _WRITE = _intermediary_low.Event.Kind.WRITE_ACCEPTED _COMPLETE = _intermediary_low.Event.Kind.COMPLETE_ACCEPTED _READ = _intermediary_low.Event.Kind.READ_ACCEPTED _METADATA = _intermediary_low.Event.Kind.METADATA_ACCEPTED _FINISH = _intermediary_low.Event.Kind.FINISH @enum.unique class _Read(enum.Enum): AWAITING_METADATA = 'awaiting metadata' READING = 'reading' AWAITING_ALLOWANCE = 'awaiting allowance' CLOSED = 'closed' @enum.unique class _HighWrite(enum.Enum): OPEN = 'open' CLOSED = 'closed' @enum.unique class _LowWrite(enum.Enum): OPEN = 'OPEN' ACTIVE = 'ACTIVE' CLOSED = 'CLOSED' class _Context(beta_interfaces.GRPCInvocationContext): def __init__(self): self._lock = threading.Lock() self._disable_next_compression = False def disable_next_request_compression(self): with self._lock: self._disable_next_compression = True def next_compression_disabled(self): with self._lock: disabled = self._disable_next_compression self._disable_next_compression = False return disabled class _RPCState(object): def __init__( self, call, request_serializer, response_deserializer, sequence_number, read, allowance, high_write, low_write, due, context): self.call = call self.request_serializer = request_serializer self.response_deserializer = response_deserializer self.sequence_number = sequence_number self.read = read self.allowance = allowance self.high_write = high_write self.low_write = low_write self.due = due self.context = context def _no_longer_due(kind, rpc_state, key, rpc_states): rpc_state.due.remove(kind) if not rpc_state.due: del rpc_states[key] class _Kernel(object): def __init__( self, channel, host, metadata_transformer, request_serializers, response_deserializers, ticket_relay): self._lock = threading.Lock() self._channel = channel self._host = host self._metadata_transformer = metadata_transformer self._request_serializers = request_serializers self._response_deserializers = response_deserializers self._relay = ticket_relay self._completion_queue = None self._rpc_states = {} self._pool = None def _on_write_event(self, operation_id, unused_event, rpc_state): if rpc_state.high_write is _HighWrite.CLOSED: rpc_state.call.complete(operation_id) rpc_state.due.add(_COMPLETE) rpc_state.due.remove(_WRITE) rpc_state.low_write = _LowWrite.CLOSED else: ticket = links.Ticket( operation_id, rpc_state.sequence_number, None, None, None, None, 1, None, None, None, None, None, None, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) rpc_state.low_write = _LowWrite.OPEN _no_longer_due(_WRITE, rpc_state, operation_id, self._rpc_states) def _on_read_event(self, operation_id, event, rpc_state): if event.bytes is None or _FINISH not in rpc_state.due: rpc_state.read = _Read.CLOSED _no_longer_due(_READ, rpc_state, operation_id, self._rpc_states) else: if 0 < rpc_state.allowance: rpc_state.allowance -= 1 rpc_state.call.read(operation_id) else: rpc_state.read = _Read.AWAITING_ALLOWANCE _no_longer_due(_READ, rpc_state, operation_id, self._rpc_states) ticket = links.Ticket( operation_id, rpc_state.sequence_number, None, None, None, None, None, None, rpc_state.response_deserializer(event.bytes), None, None, None, None, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) def _on_metadata_event(self, operation_id, event, rpc_state): if _FINISH in rpc_state.due: rpc_state.allowance -= 1 rpc_state.call.read(operation_id) rpc_state.read = _Read.READING rpc_state.due.add(_READ) rpc_state.due.remove(_METADATA) ticket = links.Ticket( operation_id, rpc_state.sequence_number, None, None, links.Ticket.Subscription.FULL, None, None, event.metadata, None, None, None, None, None, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) else: _no_longer_due(_METADATA, rpc_state, operation_id, self._rpc_states) def _on_finish_event(self, operation_id, event, rpc_state): _no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states) if event.status.code is _intermediary_low.Code.OK: termination = links.Ticket.Termination.COMPLETION elif event.status.code is _intermediary_low.Code.CANCELLED: termination = links.Ticket.Termination.CANCELLATION elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED: termination = links.Ticket.Termination.EXPIRATION elif event.status.code is _intermediary_low.Code.UNIMPLEMENTED: termination = links.Ticket.Termination.REMOTE_FAILURE elif event.status.code is _intermediary_low.Code.UNKNOWN: termination = links.Ticket.Termination.LOCAL_FAILURE else: termination = links.Ticket.Termination.TRANSMISSION_FAILURE code = _constants.LOW_STATUS_CODE_TO_HIGH_STATUS_CODE[event.status.code] ticket = links.Ticket( operation_id, rpc_state.sequence_number, None, None, None, None, None, None, None, event.metadata, code, event.status.details, termination, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) def _spin(self, completion_queue): while True: event = completion_queue.get(None) with self._lock: rpc_state = self._rpc_states.get(event.tag, None) if event.kind is _STOP: pass elif event.kind is _WRITE: self._on_write_event(event.tag, event, rpc_state) elif event.kind is _METADATA: self._on_metadata_event(event.tag, event, rpc_state) elif event.kind is _READ: self._on_read_event(event.tag, event, rpc_state) elif event.kind is _FINISH: self._on_finish_event(event.tag, event, rpc_state) elif event.kind is _COMPLETE: _no_longer_due(_COMPLETE, rpc_state, event.tag, self._rpc_states) else: logging.error('Illegal RPC event! %s', (event,)) if self._completion_queue is None and not self._rpc_states: completion_queue.stop() return def _invoke( self, operation_id, group, method, initial_metadata, payload, termination, timeout, allowance, options): """Invoke an RPC. Args: operation_id: Any object to be used as an operation ID for the RPC. group: The group to which the RPC method belongs. method: The RPC method name. initial_metadata: The initial metadata object for the RPC. payload: A payload object for the RPC or None if no payload was given at invocation-time. termination: A links.Ticket.Termination value or None indicated whether or not more writes will follow from this side of the RPC. timeout: A duration of time in seconds to allow for the RPC. allowance: The number of payloads (beyond the free first one) that the local ticket exchange mate has granted permission to be read. options: A beta_interfaces.GRPCCallOptions value or None. """ if termination is links.Ticket.Termination.COMPLETION: high_write = _HighWrite.CLOSED elif termination is None: high_write = _HighWrite.OPEN else: return transformed_initial_metadata = self._metadata_transformer(initial_metadata) request_serializer = self._request_serializers.get( (group, method), _IDENTITY) response_deserializer = self._response_deserializers.get( (group, method), _IDENTITY) call = _intermediary_low.Call( self._channel, self._completion_queue, '/%s/%s' % (group, method), self._host, time.time() + timeout) if options is not None and options.credentials is not None: call.set_credentials(options.credentials._intermediary_low_credentials) if transformed_initial_metadata is not None: for metadata_key, metadata_value in transformed_initial_metadata: call.add_metadata(metadata_key, metadata_value) call.invoke(self._completion_queue, operation_id, operation_id) if payload is None: if high_write is _HighWrite.CLOSED: call.complete(operation_id) low_write = _LowWrite.CLOSED due = set((_METADATA, _COMPLETE, _FINISH,)) else: low_write = _LowWrite.OPEN due = set((_METADATA, _FINISH,)) else: if options is not None and options.disable_compression: flags = _intermediary_low.WriteFlags.WRITE_NO_COMPRESS else: flags = 0 call.write(request_serializer(payload), operation_id, flags) low_write = _LowWrite.ACTIVE due = set((_WRITE, _METADATA, _FINISH,)) context = _Context() self._rpc_states[operation_id] = _RPCState( call, request_serializer, response_deserializer, 1, _Read.AWAITING_METADATA, 1 if allowance is None else (1 + allowance), high_write, low_write, due, context) protocol = links.Protocol(links.Protocol.Kind.INVOCATION_CONTEXT, context) ticket = links.Ticket( operation_id, 0, None, None, None, None, None, None, None, None, None, None, None, protocol) self._relay.add_value(ticket) def _advance(self, operation_id, rpc_state, payload, termination, allowance): if payload is not None: disable_compression = rpc_state.context.next_compression_disabled() if disable_compression: flags = _intermediary_low.WriteFlags.WRITE_NO_COMPRESS else: flags = 0 rpc_state.call.write( rpc_state.request_serializer(payload), operation_id, flags) rpc_state.low_write = _LowWrite.ACTIVE rpc_state.due.add(_WRITE) if allowance is not None: if rpc_state.read is _Read.AWAITING_ALLOWANCE: rpc_state.allowance += allowance - 1 rpc_state.call.read(operation_id) rpc_state.read = _Read.READING rpc_state.due.add(_READ) else: rpc_state.allowance += allowance if termination is links.Ticket.Termination.COMPLETION: rpc_state.high_write = _HighWrite.CLOSED if rpc_state.low_write is _LowWrite.OPEN: rpc_state.call.complete(operation_id) rpc_state.due.add(_COMPLETE) rpc_state.low_write = _LowWrite.CLOSED elif termination is not None: rpc_state.call.cancel() def add_ticket(self, ticket): with self._lock: if ticket.sequence_number == 0: if self._completion_queue is None: logging.error('Received invocation ticket %s after stop!', ticket) else: if (ticket.protocol is not None and ticket.protocol.kind is links.Protocol.Kind.CALL_OPTION): grpc_call_options = ticket.protocol.value else: grpc_call_options = None self._invoke( ticket.operation_id, ticket.group, ticket.method, ticket.initial_metadata, ticket.payload, ticket.termination, ticket.timeout, ticket.allowance, grpc_call_options) else: rpc_state = self._rpc_states.get(ticket.operation_id) if rpc_state is not None: self._advance( ticket.operation_id, rpc_state, ticket.payload, ticket.termination, ticket.allowance) def start(self): """Starts this object. This method must be called before attempting to exchange tickets with this object. """ with self._lock: self._completion_queue = _intermediary_low.CompletionQueue() self._pool = logging_pool.pool(1) self._pool.submit(self._spin, self._completion_queue) def stop(self): """Stops this object. This method must be called for proper termination of this object, and no attempts to exchange tickets with this object may be made after this method has been called. """ with self._lock: if not self._rpc_states: self._completion_queue.stop() self._completion_queue = None pool = self._pool pool.shutdown(wait=True) class InvocationLink(links.Link, activated.Activated): """A links.Link for use on the invocation-side of a gRPC connection. Implementations of this interface are only valid for use when activated. """ __metaclass__ = abc.ABCMeta class _InvocationLink(InvocationLink): def __init__( self, channel, host, metadata_transformer, request_serializers, response_deserializers): self._relay = relay.relay(None) self._kernel = _Kernel( channel, host, _IDENTITY if metadata_transformer is None else metadata_transformer, {} if request_serializers is None else request_serializers, {} if response_deserializers is None else response_deserializers, self._relay) def _start(self): self._relay.start() self._kernel.start() return self def _stop(self): self._kernel.stop() self._relay.stop() def accept_ticket(self, ticket): """See links.Link.accept_ticket for specification.""" self._kernel.add_ticket(ticket) def join_link(self, link): """See links.Link.join_link for specification.""" self._relay.set_behavior(link.accept_ticket) def __enter__(self): """See activated.Activated.__enter__ for specification.""" return self._start() def __exit__(self, exc_type, exc_val, exc_tb): """See activated.Activated.__exit__ for specification.""" self._stop() return False def start(self): """See activated.Activated.start for specification.""" return self._start() def stop(self): """See activated.Activated.stop for specification.""" self._stop() def invocation_link( channel, host, metadata_transformer, request_serializers, response_deserializers): """Creates an InvocationLink. Args: channel: An _intermediary_low.Channel for use by the link. host: The host to specify when invoking RPCs. metadata_transformer: A callable that takes an invocation-side initial metadata value and returns another metadata value to send in its place. May be None. request_serializers: A dict from group-method pair to request object serialization behavior. response_deserializers: A dict from group-method pair to response object deserialization behavior. Returns: An InvocationLink. """ return _InvocationLink( channel, host, metadata_transformer, request_serializers, response_deserializers) grpc-0.11.1/src/python/grpcio/grpc/_links/service.py0000644000175000017500000004246212600663151022546 0ustar apollockapollock# 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. """The RPC-service-side bridge between RPC Framework and GRPC-on-the-wire.""" import abc import enum import logging import threading import time from grpc._adapter import _intermediary_low from grpc._links import _constants from grpc.beta import interfaces as beta_interfaces from grpc.framework.foundation import logging_pool from grpc.framework.foundation import relay from grpc.framework.interfaces.links import links _IDENTITY = lambda x: x _TERMINATION_KIND_TO_CODE = { links.Ticket.Termination.COMPLETION: _intermediary_low.Code.OK, links.Ticket.Termination.CANCELLATION: _intermediary_low.Code.CANCELLED, links.Ticket.Termination.EXPIRATION: _intermediary_low.Code.DEADLINE_EXCEEDED, links.Ticket.Termination.SHUTDOWN: _intermediary_low.Code.UNAVAILABLE, links.Ticket.Termination.RECEPTION_FAILURE: _intermediary_low.Code.INTERNAL, links.Ticket.Termination.TRANSMISSION_FAILURE: _intermediary_low.Code.INTERNAL, links.Ticket.Termination.LOCAL_FAILURE: _intermediary_low.Code.UNKNOWN, links.Ticket.Termination.REMOTE_FAILURE: _intermediary_low.Code.UNKNOWN, } _STOP = _intermediary_low.Event.Kind.STOP _WRITE = _intermediary_low.Event.Kind.WRITE_ACCEPTED _COMPLETE = _intermediary_low.Event.Kind.COMPLETE_ACCEPTED _SERVICE = _intermediary_low.Event.Kind.SERVICE_ACCEPTED _READ = _intermediary_low.Event.Kind.READ_ACCEPTED _FINISH = _intermediary_low.Event.Kind.FINISH @enum.unique class _Read(enum.Enum): READING = 'reading' # TODO(issue 2916): This state will again be necessary after eliminating the # "early_read" field of _RPCState and going back to only reading when granted # allowance to read. # AWAITING_ALLOWANCE = 'awaiting allowance' CLOSED = 'closed' @enum.unique class _HighWrite(enum.Enum): OPEN = 'open' CLOSED = 'closed' @enum.unique class _LowWrite(enum.Enum): """The possible categories of low-level write state.""" OPEN = 'OPEN' ACTIVE = 'ACTIVE' CLOSED = 'CLOSED' class _Context(beta_interfaces.GRPCServicerContext): def __init__(self, call): self._lock = threading.Lock() self._call = call self._disable_next_compression = False def peer(self): with self._lock: return self._call.peer() def disable_next_response_compression(self): with self._lock: self._disable_next_compression = True def next_compression_disabled(self): with self._lock: disabled = self._disable_next_compression self._disable_next_compression = False return disabled class _RPCState(object): def __init__( self, request_deserializer, response_serializer, sequence_number, read, early_read, allowance, high_write, low_write, premetadataed, terminal_metadata, code, message, due, context): self.request_deserializer = request_deserializer self.response_serializer = response_serializer self.sequence_number = sequence_number self.read = read # TODO(issue 2916): Eliminate this by eliminating the necessity of calling # call.read just to advance the RPC. self.early_read = early_read # A raw (not deserialized) read. self.allowance = allowance self.high_write = high_write self.low_write = low_write self.premetadataed = premetadataed self.terminal_metadata = terminal_metadata self.code = code self.message = message self.due = due self.context = context def _no_longer_due(kind, rpc_state, key, rpc_states): rpc_state.due.remove(kind) if not rpc_state.due: del rpc_states[key] def _metadatafy(call, metadata): for metadata_key, metadata_value in metadata: call.add_metadata(metadata_key, metadata_value) def _status(termination_kind, high_code, details): low_details = b'' if details is None else details if high_code is None: low_code = _TERMINATION_KIND_TO_CODE[termination_kind] else: low_code = _constants.HIGH_STATUS_CODE_TO_LOW_STATUS_CODE[high_code] return _intermediary_low.Status(low_code, low_details) class _Kernel(object): def __init__(self, request_deserializers, response_serializers, ticket_relay): self._lock = threading.Lock() self._request_deserializers = request_deserializers self._response_serializers = response_serializers self._relay = ticket_relay self._completion_queue = None self._due = set() self._server = None self._rpc_states = {} self._pool = None def _on_service_acceptance_event(self, event, server): server.service(None) service_acceptance = event.service_acceptance call = service_acceptance.call call.accept(self._completion_queue, call) try: group, method = service_acceptance.method.split('/')[1:3] except ValueError: logging.info('Illegal path "%s"!', service_acceptance.method) return request_deserializer = self._request_deserializers.get( (group, method), _IDENTITY) response_serializer = self._response_serializers.get( (group, method), _IDENTITY) call.read(call) context = _Context(call) self._rpc_states[call] = _RPCState( request_deserializer, response_serializer, 1, _Read.READING, None, 1, _HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None, set((_READ, _FINISH,)), context) protocol = links.Protocol(links.Protocol.Kind.SERVICER_CONTEXT, context) ticket = links.Ticket( call, 0, group, method, links.Ticket.Subscription.FULL, service_acceptance.deadline - time.time(), None, event.metadata, None, None, None, None, None, protocol) self._relay.add_value(ticket) def _on_read_event(self, event): call = event.tag rpc_state = self._rpc_states[call] if event.bytes is None: rpc_state.read = _Read.CLOSED payload = None termination = links.Ticket.Termination.COMPLETION _no_longer_due(_READ, rpc_state, call, self._rpc_states) else: if 0 < rpc_state.allowance: payload = rpc_state.request_deserializer(event.bytes) termination = None rpc_state.allowance -= 1 call.read(call) else: rpc_state.early_read = event.bytes _no_longer_due(_READ, rpc_state, call, self._rpc_states) return # TODO(issue 2916): Instead of returning: # rpc_state.read = _Read.AWAITING_ALLOWANCE ticket = links.Ticket( call, rpc_state.sequence_number, None, None, None, None, None, None, payload, None, None, None, termination, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) def _on_write_event(self, event): call = event.tag rpc_state = self._rpc_states[call] if rpc_state.high_write is _HighWrite.CLOSED: if rpc_state.terminal_metadata is not None: _metadatafy(call, rpc_state.terminal_metadata) status = _status( links.Ticket.Termination.COMPLETION, rpc_state.code, rpc_state.message) call.status(status, call) rpc_state.low_write = _LowWrite.CLOSED rpc_state.due.add(_COMPLETE) rpc_state.due.remove(_WRITE) else: ticket = links.Ticket( call, rpc_state.sequence_number, None, None, None, None, 1, None, None, None, None, None, None, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) rpc_state.low_write = _LowWrite.OPEN _no_longer_due(_WRITE, rpc_state, call, self._rpc_states) def _on_finish_event(self, event): call = event.tag rpc_state = self._rpc_states[call] _no_longer_due(_FINISH, rpc_state, call, self._rpc_states) code = event.status.code if code is _intermediary_low.Code.OK: return if code is _intermediary_low.Code.CANCELLED: termination = links.Ticket.Termination.CANCELLATION elif code is _intermediary_low.Code.DEADLINE_EXCEEDED: termination = links.Ticket.Termination.EXPIRATION else: termination = links.Ticket.Termination.TRANSMISSION_FAILURE ticket = links.Ticket( call, rpc_state.sequence_number, None, None, None, None, None, None, None, None, None, None, termination, None) rpc_state.sequence_number += 1 self._relay.add_value(ticket) def _spin(self, completion_queue, server): while True: event = completion_queue.get(None) with self._lock: if event.kind is _STOP: self._due.remove(_STOP) elif event.kind is _READ: self._on_read_event(event) elif event.kind is _WRITE: self._on_write_event(event) elif event.kind is _COMPLETE: _no_longer_due( _COMPLETE, self._rpc_states.get(event.tag), event.tag, self._rpc_states) elif event.kind is _intermediary_low.Event.Kind.FINISH: self._on_finish_event(event) elif event.kind is _SERVICE: if self._server is None: self._due.remove(_SERVICE) else: self._on_service_acceptance_event(event, server) else: logging.error('Illegal event! %s', (event,)) if not self._due and not self._rpc_states: completion_queue.stop() return def add_ticket(self, ticket): with self._lock: call = ticket.operation_id rpc_state = self._rpc_states.get(call) if rpc_state is None: return if ticket.initial_metadata is not None: _metadatafy(call, ticket.initial_metadata) call.premetadata() rpc_state.premetadataed = True elif not rpc_state.premetadataed: if (ticket.terminal_metadata is not None or ticket.payload is not None or ticket.termination is not None or ticket.code is not None or ticket.message is not None): call.premetadata() rpc_state.premetadataed = True if ticket.allowance is not None: if rpc_state.early_read is None: rpc_state.allowance += ticket.allowance else: payload = rpc_state.request_deserializer(rpc_state.early_read) rpc_state.allowance += ticket.allowance - 1 rpc_state.early_read = None if rpc_state.read is _Read.READING: call.read(call) rpc_state.due.add(_READ) termination = None else: termination = links.Ticket.Termination.COMPLETION early_read_ticket = links.Ticket( call, rpc_state.sequence_number, None, None, None, None, None, None, payload, None, None, None, termination, None) rpc_state.sequence_number += 1 self._relay.add_value(early_read_ticket) if ticket.payload is not None: disable_compression = rpc_state.context.next_compression_disabled() if disable_compression: flags = _intermediary_low.WriteFlags.WRITE_NO_COMPRESS else: flags = 0 call.write(rpc_state.response_serializer(ticket.payload), call, flags) rpc_state.due.add(_WRITE) rpc_state.low_write = _LowWrite.ACTIVE if ticket.terminal_metadata is not None: rpc_state.terminal_metadata = ticket.terminal_metadata if ticket.code is not None: rpc_state.code = ticket.code if ticket.message is not None: rpc_state.message = ticket.message if ticket.termination is links.Ticket.Termination.COMPLETION: rpc_state.high_write = _HighWrite.CLOSED if rpc_state.low_write is _LowWrite.OPEN: if rpc_state.terminal_metadata is not None: _metadatafy(call, rpc_state.terminal_metadata) status = _status( links.Ticket.Termination.COMPLETION, rpc_state.code, rpc_state.message) call.status(status, call) rpc_state.due.add(_COMPLETE) rpc_state.low_write = _LowWrite.CLOSED elif ticket.termination is not None: if rpc_state.terminal_metadata is not None: _metadatafy(call, rpc_state.terminal_metadata) status = _status( ticket.termination, rpc_state.code, rpc_state.message) call.status(status, call) rpc_state.due.add(_COMPLETE) def add_port(self, address, server_credentials): with self._lock: if self._server is None: self._completion_queue = _intermediary_low.CompletionQueue() self._server = _intermediary_low.Server(self._completion_queue) if server_credentials is None: return self._server.add_http2_addr(address) else: return self._server.add_secure_http2_addr(address, server_credentials) def start(self): with self._lock: if self._server is None: self._completion_queue = _intermediary_low.CompletionQueue() self._server = _intermediary_low.Server(self._completion_queue) self._pool = logging_pool.pool(1) self._pool.submit(self._spin, self._completion_queue, self._server) self._server.start() self._server.service(None) self._due.add(_SERVICE) def begin_stop(self): with self._lock: self._server.stop() self._due.add(_STOP) self._server = None def end_stop(self): with self._lock: pool = self._pool pool.shutdown(wait=True) class ServiceLink(links.Link): """A links.Link for use on the service-side of a gRPC connection. Implementations of this interface are only valid for use between calls to their start method and one of their stop methods. """ @abc.abstractmethod def add_port(self, address, server_credentials): """Adds a port on which to service RPCs after this link has been started. Args: address: The address on which to service RPCs with a port number of zero requesting that a port number be automatically selected and used. server_credentials: An _intermediary_low.ServerCredentials object, or None for insecure service. Returns: An integer port on which RPCs will be serviced after this link has been started. This is typically the same number as the port number contained in the passed address, but will likely be different if the port number contained in the passed address was zero. """ raise NotImplementedError() @abc.abstractmethod def start(self): """Starts this object. This method must be called before attempting to use this Link in ticket exchange. """ raise NotImplementedError() @abc.abstractmethod def begin_stop(self): """Indicate imminent link stop and immediate rejection of new RPCs. New RPCs will be rejected as soon as this method is called, but ongoing RPCs will be allowed to continue until they terminate. This method does not block. """ raise NotImplementedError() @abc.abstractmethod def end_stop(self): """Finishes stopping this link. begin_stop must have been called exactly once before calling this method. All in-progress RPCs will be terminated immediately. """ raise NotImplementedError() class _ServiceLink(ServiceLink): def __init__(self, request_deserializers, response_serializers): self._relay = relay.relay(None) self._kernel = _Kernel( {} if request_deserializers is None else request_deserializers, {} if response_serializers is None else response_serializers, self._relay) def accept_ticket(self, ticket): self._kernel.add_ticket(ticket) def join_link(self, link): self._relay.set_behavior(link.accept_ticket) def add_port(self, address, server_credentials): return self._kernel.add_port(address, server_credentials) def start(self): self._relay.start() return self._kernel.start() def begin_stop(self): self._kernel.begin_stop() def end_stop(self): self._kernel.end_stop() self._relay.stop() def service_link(request_deserializers, response_serializers): """Creates a ServiceLink. Args: request_deserializers: A dict from group-method pair to request object deserialization behavior. response_serializers: A dict from group-method pair to response ojbect serialization behavior. Returns: A ServiceLink. """ return _ServiceLink(request_deserializers, response_serializers) grpc-0.11.1/src/python/grpcio/grpc/_links/__init__.py0000644000175000017500000000277212600663151022645 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/__init__.py0000644000175000017500000000277212600663151021366 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/_adapter/0000755000175000017500000000000012600663151021024 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_adapter/_intermediary_low.py0000644000175000017500000002346212600663151025121 0ustar apollockapollock# 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. """Temporary old _low-like layer. Eases refactoring burden while we overhaul the Python framework. Plan: The layers used to look like: ... # outside _adapter fore.py + rear.py # visible outside _adapter _low _c The layers currently look like: ... # outside _adapter fore.py + rear.py # visible outside _adapter _low_intermediary # adapter for new '_low' to old '_low' _low # new '_low' _c # new '_c' We will later remove _low_intermediary after refactoring of fore.py and rear.py according to the ticket system refactoring and get: ... # outside _adapter, refactored fore.py + rear.py # visible outside _adapter, refactored _low # new '_low' _c # new '_c' """ import collections import enum from grpc._adapter import _low from grpc._adapter import _types _IGNORE_ME_TAG = object() Code = _types.StatusCode WriteFlags = _types.OpWriteFlags class Status(collections.namedtuple('Status', ['code', 'details'])): """Describes an RPC's overall status.""" class ServiceAcceptance( collections.namedtuple( 'ServiceAcceptance', ['call', 'method', 'host', 'deadline'])): """Describes an RPC on the service side at the start of service.""" class Event( collections.namedtuple( 'Event', ['kind', 'tag', 'write_accepted', 'complete_accepted', 'service_acceptance', 'bytes', 'status', 'metadata'])): """Describes an event emitted from a completion queue.""" @enum.unique class Kind(enum.Enum): """Describes the kind of an event.""" STOP = object() WRITE_ACCEPTED = object() COMPLETE_ACCEPTED = object() SERVICE_ACCEPTED = object() READ_ACCEPTED = object() METADATA_ACCEPTED = object() FINISH = object() class _TagAdapter(collections.namedtuple('_TagAdapter', [ 'user_tag', 'kind' ])): pass class Call(object): """Adapter from old _low.Call interface to new _low.Call.""" def __init__(self, channel, completion_queue, method, host, deadline): self._internal = channel._internal.create_call( completion_queue._internal, method, host, deadline) self._metadata = [] @staticmethod def _from_internal(internal): call = Call.__new__(Call) call._internal = internal call._metadata = [] return call def invoke(self, completion_queue, metadata_tag, finish_tag): err0 = self._internal.start_batch([ _types.OpArgs.send_initial_metadata(self._metadata) ], _IGNORE_ME_TAG) err1 = self._internal.start_batch([ _types.OpArgs.recv_initial_metadata() ], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED)) err2 = self._internal.start_batch([ _types.OpArgs.recv_status_on_client() ], _TagAdapter(finish_tag, Event.Kind.FINISH)) return err0 if err0 != _types.CallError.OK else err1 if err1 != _types.CallError.OK else err2 if err2 != _types.CallError.OK else _types.CallError.OK def write(self, message, tag, flags): return self._internal.start_batch([ _types.OpArgs.send_message(message, flags) ], _TagAdapter(tag, Event.Kind.WRITE_ACCEPTED)) def complete(self, tag): return self._internal.start_batch([ _types.OpArgs.send_close_from_client() ], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED)) def accept(self, completion_queue, tag): return self._internal.start_batch([ _types.OpArgs.recv_close_on_server() ], _TagAdapter(tag, Event.Kind.FINISH)) def add_metadata(self, key, value): self._metadata.append((key, value)) def premetadata(self): result = self._internal.start_batch([ _types.OpArgs.send_initial_metadata(self._metadata) ], _IGNORE_ME_TAG) self._metadata = [] return result def read(self, tag): return self._internal.start_batch([ _types.OpArgs.recv_message() ], _TagAdapter(tag, Event.Kind.READ_ACCEPTED)) def status(self, status, tag): return self._internal.start_batch([ _types.OpArgs.send_status_from_server(self._metadata, status.code, status.details) ], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED)) def cancel(self): return self._internal.cancel() def peer(self): return self._internal.peer() def set_credentials(self, creds): return self._internal.set_credentials(creds._internal) class Channel(object): """Adapter from old _low.Channel interface to new _low.Channel.""" def __init__(self, hostport, client_credentials, server_host_override=None): args = [] if server_host_override: args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override)) creds = None if client_credentials: creds = client_credentials._internal self._internal = _low.Channel(hostport, args, creds) class CompletionQueue(object): """Adapter from old _low.CompletionQueue interface to new _low.CompletionQueue.""" def __init__(self): self._internal = _low.CompletionQueue() def get(self, deadline=None): if deadline is None: ev = self._internal.next() else: ev = self._internal.next(deadline) if ev is None: return None elif ev.tag is _IGNORE_ME_TAG: return self.get(deadline) elif ev.type == _types.EventType.QUEUE_SHUTDOWN: kind = Event.Kind.STOP tag = None write_accepted = None complete_accepted = None service_acceptance = None message_bytes = None status = None metadata = None elif ev.type == _types.EventType.OP_COMPLETE: kind = ev.tag.kind tag = ev.tag.user_tag write_accepted = ev.success if kind == Event.Kind.WRITE_ACCEPTED else None complete_accepted = ev.success if kind == Event.Kind.COMPLETE_ACCEPTED else None service_acceptance = ServiceAcceptance(Call._from_internal(ev.call), ev.call_details.method, ev.call_details.host, ev.call_details.deadline) if kind == Event.Kind.SERVICE_ACCEPTED else None message_bytes = ev.results[0].message if kind == Event.Kind.READ_ACCEPTED else None status = Status(ev.results[0].status.code, ev.results[0].status.details) if (kind == Event.Kind.FINISH and ev.results[0].status) else Status(_types.StatusCode.CANCELLED if ev.results[0].cancelled else _types.StatusCode.OK, '') if len(ev.results) > 0 and ev.results[0].cancelled is not None else None metadata = ev.results[0].initial_metadata if (kind in [Event.Kind.SERVICE_ACCEPTED, Event.Kind.METADATA_ACCEPTED]) else (ev.results[0].trailing_metadata if kind == Event.Kind.FINISH else None) else: raise RuntimeError('unknown event') result_ev = Event(kind=kind, tag=tag, write_accepted=write_accepted, complete_accepted=complete_accepted, service_acceptance=service_acceptance, bytes=message_bytes, status=status, metadata=metadata) return result_ev def stop(self): self._internal.shutdown() class Server(object): """Adapter from old _low.Server interface to new _low.Server.""" def __init__(self, completion_queue): self._internal = _low.Server(completion_queue._internal, []) self._internal_cq = completion_queue._internal def add_http2_addr(self, addr): return self._internal.add_http2_port(addr) def add_secure_http2_addr(self, addr, server_credentials): if server_credentials is None: return self._internal.add_http2_port(addr, None) else: return self._internal.add_http2_port(addr, server_credentials._internal) def start(self): return self._internal.start() def service(self, tag): return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED)) def stop(self): return self._internal.shutdown(_TagAdapter(None, Event.Kind.STOP)) class ClientCredentials(object): """Adapter from old _low.ClientCredentials interface to new _low.ClientCredentials.""" def __init__(self, root_certificates, private_key, certificate_chain): self._internal = _low.ClientCredentials.ssl(root_certificates, private_key, certificate_chain) class ServerCredentials(object): """Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials.""" def __init__(self, root_credentials, pair_sequence, force_client_auth): self._internal = _low.ServerCredentials.ssl( root_credentials, list(pair_sequence), force_client_auth) grpc-0.11.1/src/python/grpcio/grpc/_adapter/fore.py0000644000175000017500000003072712600663151022342 0ustar apollockapollock# 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. """The RPC-service-side bridge between RPC Framework and GRPC-on-the-wire.""" import enum import logging import threading import time from grpc._adapter import _common from grpc._adapter import _intermediary_low as _low from grpc.framework.base import interfaces as base_interfaces from grpc.framework.base import null from grpc.framework.foundation import activated from grpc.framework.foundation import logging_pool _THREAD_POOL_SIZE = 10 @enum.unique class _LowWrite(enum.Enum): """The possible categories of low-level write state.""" OPEN = 'OPEN' ACTIVE = 'ACTIVE' CLOSED = 'CLOSED' def _write(call, rpc_state, payload): serialized_payload = rpc_state.serializer(payload) if rpc_state.write.low is _LowWrite.OPEN: call.write(serialized_payload, call, 0) rpc_state.write.low = _LowWrite.ACTIVE else: rpc_state.write.pending.append(serialized_payload) def _status(call, rpc_state): call.status(_low.Status(_low.Code.OK, ''), call) rpc_state.write.low = _LowWrite.CLOSED class ForeLink(base_interfaces.ForeLink, activated.Activated): """A service-side bridge between RPC Framework and the C-ish _low code.""" def __init__( self, pool, request_deserializers, response_serializers, root_certificates, key_chain_pairs, port=None): """Constructor. Args: pool: A thread pool. request_deserializers: A dict from RPC method names to request object deserializer behaviors. response_serializers: A dict from RPC method names to response object serializer behaviors. root_certificates: The PEM-encoded client root certificates as a bytestring or None. key_chain_pairs: A sequence of PEM-encoded private key-certificate chain pairs. port: The port on which to serve, or None to have a port selected automatically. """ self._condition = threading.Condition() self._pool = pool self._request_deserializers = request_deserializers self._response_serializers = response_serializers self._root_certificates = root_certificates self._key_chain_pairs = key_chain_pairs self._requested_port = port self._rear_link = null.NULL_REAR_LINK self._completion_queue = None self._server = None self._rpc_states = {} self._spinning = False self._port = None def _on_stop_event(self): self._spinning = False self._condition.notify_all() def _on_service_acceptance_event(self, event, server): """Handle a service invocation event.""" service_acceptance = event.service_acceptance if service_acceptance is None: return call = service_acceptance.call call.accept(self._completion_queue, call) # TODO(nathaniel): Metadata support. call.premetadata() call.read(call) method = service_acceptance.method self._rpc_states[call] = _common.CommonRPCState( _common.WriteState(_LowWrite.OPEN, _common.HighWrite.OPEN, []), 1, self._request_deserializers[method], self._response_serializers[method]) ticket = base_interfaces.FrontToBackTicket( call, 0, base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT, method, base_interfaces.ServicedSubscription.Kind.FULL, None, None, service_acceptance.deadline - time.time()) self._rear_link.accept_front_to_back_ticket(ticket) server.service(None) def _on_read_event(self, event): """Handle data arriving during an RPC.""" call = event.tag rpc_state = self._rpc_states.get(call, None) if rpc_state is None: return sequence_number = rpc_state.sequence_number rpc_state.sequence_number += 1 if event.bytes is None: ticket = base_interfaces.FrontToBackTicket( call, sequence_number, base_interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None, None, None) else: call.read(call) ticket = base_interfaces.FrontToBackTicket( call, sequence_number, base_interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None, None, rpc_state.deserializer(event.bytes), None) self._rear_link.accept_front_to_back_ticket(ticket) def _on_write_event(self, event): call = event.tag rpc_state = self._rpc_states.get(call, None) if rpc_state is None: return if rpc_state.write.pending: serialized_payload = rpc_state.write.pending.pop(0) call.write(serialized_payload, call, 0) elif rpc_state.write.high is _common.HighWrite.CLOSED: _status(call, rpc_state) else: rpc_state.write.low = _LowWrite.OPEN def _on_complete_event(self, event): if not event.complete_accepted: logging.error('Complete not accepted! %s', (event,)) call = event.tag rpc_state = self._rpc_states.pop(call, None) if rpc_state is None: return sequence_number = rpc_state.sequence_number rpc_state.sequence_number += 1 ticket = base_interfaces.FrontToBackTicket( call, sequence_number, base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None, None, None, None, None) self._rear_link.accept_front_to_back_ticket(ticket) def _on_finish_event(self, event): """Handle termination of an RPC.""" call = event.tag rpc_state = self._rpc_states.pop(call, None) if rpc_state is None: return code = event.status.code if code is _low.Code.OK: return sequence_number = rpc_state.sequence_number rpc_state.sequence_number += 1 if code is _low.Code.CANCELLED: ticket = base_interfaces.FrontToBackTicket( call, sequence_number, base_interfaces.FrontToBackTicket.Kind.CANCELLATION, None, None, None, None, None) elif code is _low.Code.DEADLINE_EXCEEDED: ticket = base_interfaces.FrontToBackTicket( call, sequence_number, base_interfaces.FrontToBackTicket.Kind.EXPIRATION, None, None, None, None, None) else: # TODO(nathaniel): Better mapping of codes to ticket-categories ticket = base_interfaces.FrontToBackTicket( call, sequence_number, base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None, None, None, None, None) self._rear_link.accept_front_to_back_ticket(ticket) def _spin(self, completion_queue, server): while True: event = completion_queue.get(None) with self._condition: if event.kind is _low.Event.Kind.STOP: self._on_stop_event() return elif self._server is None: continue elif event.kind is _low.Event.Kind.SERVICE_ACCEPTED: self._on_service_acceptance_event(event, server) elif event.kind is _low.Event.Kind.READ_ACCEPTED: self._on_read_event(event) elif event.kind is _low.Event.Kind.WRITE_ACCEPTED: self._on_write_event(event) elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED: self._on_complete_event(event) elif event.kind is _low.Event.Kind.FINISH: self._on_finish_event(event) else: logging.error('Illegal event! %s', (event,)) def _continue(self, call, payload): rpc_state = self._rpc_states.get(call, None) if rpc_state is None: return _write(call, rpc_state, payload) def _complete(self, call, payload): """Handle completion of the writes of an RPC.""" rpc_state = self._rpc_states.get(call, None) if rpc_state is None: return if rpc_state.write.low is _LowWrite.OPEN: if payload is None: _status(call, rpc_state) else: _write(call, rpc_state, payload) elif rpc_state.write.low is _LowWrite.ACTIVE: if payload is not None: rpc_state.write.pending.append(rpc_state.serializer(payload)) else: raise ValueError('Called to complete after having already completed!') rpc_state.write.high = _common.HighWrite.CLOSED def _cancel(self, call): call.cancel() self._rpc_states.pop(call, None) def join_rear_link(self, rear_link): """See base_interfaces.ForeLink.join_rear_link for specification.""" self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link def _start(self): """Starts this ForeLink. This method must be called before attempting to exchange tickets with this object. """ with self._condition: address = '[::]:%d' % ( 0 if self._requested_port is None else self._requested_port) self._completion_queue = _low.CompletionQueue() if self._root_certificates is None and not self._key_chain_pairs: self._server = _low.Server(self._completion_queue) self._port = self._server.add_http2_addr(address) else: server_credentials = _low.ServerCredentials( self._root_certificates, self._key_chain_pairs, False) self._server = _low.Server(self._completion_queue) self._port = self._server.add_secure_http2_addr( address, server_credentials) self._server.start() self._server.service(None) self._pool.submit(self._spin, self._completion_queue, self._server) self._spinning = True return self # TODO(nathaniel): Expose graceful-shutdown semantics in which this object # enters a state in which it finishes ongoing RPCs but refuses new ones. def _stop(self): """Stops this ForeLink. This method must be called for proper termination of this object, and no attempts to exchange tickets with this object may be made after this method has been called. """ with self._condition: self._server.stop() # TODO(nathaniel): Yep, this is weird. Deleting a server shouldn't have a # behaviorally significant side-effect. self._server = None self._completion_queue.stop() while self._spinning: self._condition.wait() self._port = None def __enter__(self): """See activated.Activated.__enter__ for specification.""" return self._start() def __exit__(self, exc_type, exc_val, exc_tb): """See activated.Activated.__exit__ for specification.""" self._stop() return False def start(self): """See activated.Activated.start for specification.""" return self._start() def stop(self): """See activated.Activated.stop for specification.""" self._stop() def port(self): """Identifies the port on which this ForeLink is servicing RPCs. Returns: The number of the port on which this ForeLink is servicing RPCs, or None if this ForeLink is not currently activated and servicing RPCs. """ with self._condition: return self._port def accept_back_to_front_ticket(self, ticket): """See base_interfaces.ForeLink.accept_back_to_front_ticket for spec.""" with self._condition: if self._server is None: return if ticket.kind is base_interfaces.BackToFrontTicket.Kind.CONTINUATION: self._continue(ticket.operation_id, ticket.payload) elif ticket.kind is base_interfaces.BackToFrontTicket.Kind.COMPLETION: self._complete(ticket.operation_id, ticket.payload) else: self._cancel(ticket.operation_id) grpc-0.11.1/src/python/grpcio/grpc/_adapter/_common.py0000644000175000017500000000553312600663151023033 0ustar apollockapollock# 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. """State used by both invocation-side and service-side code.""" import enum @enum.unique class HighWrite(enum.Enum): """The possible categories of high-level write state.""" OPEN = 'OPEN' CLOSED = 'CLOSED' class WriteState(object): """A description of the state of writing to an RPC. Attributes: low: A side-specific value describing the low-level state of writing. high: A HighWrite value describing the high-level state of writing. pending: A list of bytestrings for the RPC waiting to be written to the other side of the RPC. """ def __init__(self, low, high, pending): self.low = low self.high = high self.pending = pending class CommonRPCState(object): """A description of an RPC's state. Attributes: write: A WriteState describing the state of writing to the RPC. sequence_number: The lowest-unused sequence number for use in generating tickets locally describing the progress of the RPC. deserializer: The behavior to be used to deserialize payload bytestreams taken off the wire. serializer: The behavior to be used to serialize payloads to be sent on the wire. """ def __init__(self, write, sequence_number, deserializer, serializer): self.write = write self.sequence_number = sequence_number self.deserializer = deserializer self.serializer = serializer grpc-0.11.1/src/python/grpcio/grpc/_adapter/_types.py0000644000175000017500000002762212600663151022712 0ustar apollockapollock# 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. import abc import collections import enum class GrpcChannelArgumentKeys(enum.Enum): """Mirrors keys used in grpc_channel_args for GRPC-specific arguments.""" SSL_TARGET_NAME_OVERRIDE = 'grpc.ssl_target_name_override' @enum.unique class CallError(enum.IntEnum): """Mirrors grpc_call_error in the C core.""" OK = 0 ERROR = 1 ERROR_NOT_ON_SERVER = 2 ERROR_NOT_ON_CLIENT = 3 ERROR_ALREADY_ACCEPTED = 4 ERROR_ALREADY_INVOKED = 5 ERROR_NOT_INVOKED = 6 ERROR_ALREADY_FINISHED = 7 ERROR_TOO_MANY_OPERATIONS = 8 ERROR_INVALID_FLAGS = 9 ERROR_INVALID_METADATA = 10 @enum.unique class StatusCode(enum.IntEnum): """Mirrors grpc_status_code in the C core.""" OK = 0 CANCELLED = 1 UNKNOWN = 2 INVALID_ARGUMENT = 3 DEADLINE_EXCEEDED = 4 NOT_FOUND = 5 ALREADY_EXISTS = 6 PERMISSION_DENIED = 7 RESOURCE_EXHAUSTED = 8 FAILED_PRECONDITION = 9 ABORTED = 10 OUT_OF_RANGE = 11 UNIMPLEMENTED = 12 INTERNAL = 13 UNAVAILABLE = 14 DATA_LOSS = 15 UNAUTHENTICATED = 16 @enum.unique class OpWriteFlags(enum.IntEnum): """Mirrors defined write-flag constants in the C core.""" WRITE_BUFFER_HINT = 1 WRITE_NO_COMPRESS = 2 @enum.unique class OpType(enum.IntEnum): """Mirrors grpc_op_type in the C core.""" SEND_INITIAL_METADATA = 0 SEND_MESSAGE = 1 SEND_CLOSE_FROM_CLIENT = 2 SEND_STATUS_FROM_SERVER = 3 RECV_INITIAL_METADATA = 4 RECV_MESSAGE = 5 RECV_STATUS_ON_CLIENT = 6 RECV_CLOSE_ON_SERVER = 7 @enum.unique class EventType(enum.IntEnum): """Mirrors grpc_completion_type in the C core.""" QUEUE_SHUTDOWN = 0 QUEUE_TIMEOUT = 1 # if seen on the Python side, something went horridly wrong OP_COMPLETE = 2 @enum.unique class ConnectivityState(enum.IntEnum): """Mirrors grpc_connectivity_state in the C core.""" IDLE = 0 CONNECTING = 1 READY = 2 TRANSIENT_FAILURE = 3 FATAL_FAILURE = 4 class Status(collections.namedtuple( 'Status', [ 'code', 'details', ])): """The end status of a GRPC call. Attributes: code (StatusCode): ... details (str): ... """ class CallDetails(collections.namedtuple( 'CallDetails', [ 'method', 'host', 'deadline', ])): """Provides information to the server about the client's call. Attributes: method (str): ... host (str): ... deadline (float): ... """ class OpArgs(collections.namedtuple( 'OpArgs', [ 'type', 'initial_metadata', 'trailing_metadata', 'message', 'status', 'write_flags', ])): """Arguments passed into a GRPC operation. Attributes: type (OpType): ... initial_metadata (sequence of 2-sequence of str): Only valid if type == OpType.SEND_INITIAL_METADATA, else is None. trailing_metadata (sequence of 2-sequence of str): Only valid if type == OpType.SEND_STATUS_FROM_SERVER, else is None. message (bytes): Only valid if type == OpType.SEND_MESSAGE, else is None. status (Status): Only valid if type == OpType.SEND_STATUS_FROM_SERVER, else is None. write_flags (int): a bit OR'ing of 0 or more OpWriteFlags values. """ @staticmethod def send_initial_metadata(initial_metadata): return OpArgs(OpType.SEND_INITIAL_METADATA, initial_metadata, None, None, None, 0) @staticmethod def send_message(message, flags): return OpArgs(OpType.SEND_MESSAGE, None, None, message, None, flags) @staticmethod def send_close_from_client(): return OpArgs(OpType.SEND_CLOSE_FROM_CLIENT, None, None, None, None, 0) @staticmethod def send_status_from_server(trailing_metadata, status_code, status_details): return OpArgs(OpType.SEND_STATUS_FROM_SERVER, None, trailing_metadata, None, Status(status_code, status_details), 0) @staticmethod def recv_initial_metadata(): return OpArgs(OpType.RECV_INITIAL_METADATA, None, None, None, None, 0); @staticmethod def recv_message(): return OpArgs(OpType.RECV_MESSAGE, None, None, None, None, 0) @staticmethod def recv_status_on_client(): return OpArgs(OpType.RECV_STATUS_ON_CLIENT, None, None, None, None, 0) @staticmethod def recv_close_on_server(): return OpArgs(OpType.RECV_CLOSE_ON_SERVER, None, None, None, None, 0) class OpResult(collections.namedtuple( 'OpResult', [ 'type', 'initial_metadata', 'trailing_metadata', 'message', 'status', 'cancelled', ])): """Results received from a GRPC operation. Attributes: type (OpType): ... initial_metadata (sequence of 2-sequence of str): Only valid if type == OpType.RECV_INITIAL_METADATA, else is None. trailing_metadata (sequence of 2-sequence of str): Only valid if type == OpType.RECV_STATUS_ON_CLIENT, else is None. message (bytes): Only valid if type == OpType.RECV_MESSAGE, else is None. status (Status): Only valid if type == OpType.RECV_STATUS_ON_CLIENT, else is None. cancelled (bool): Only valid if type == OpType.RECV_CLOSE_ON_SERVER, else is None. """ class Event(collections.namedtuple( 'Event', [ 'type', 'tag', 'call', 'call_details', 'results', 'success', ])): """An event received from a GRPC completion queue. Attributes: type (EventType): ... tag (object): ... call (Call): The Call object associated with this event (if there is one, else None). call_details (CallDetails): The call details associated with the server-side call (if there is such information, else None). results (list of OpResult): ... success (bool): ... """ class CompletionQueue: __metaclass__ = abc.ABCMeta @abc.abstractmethod def __init__(self): pass def __iter__(self): """This class may be iterated over. This is the equivalent of calling next() repeatedly with an absolute deadline of None (i.e. no deadline). """ return self @abc.abstractmethod def next(self, deadline=float('+inf')): """Get the next event on this completion queue. Args: deadline (float): absolute deadline in seconds from the Python epoch, or None for no deadline. Returns: Event: ... """ pass @abc.abstractmethod def shutdown(self): """Begin the shutdown process of this completion queue. Note that this does not immediately destroy the completion queue. Nevertheless, user code should not pass it around after invoking this. """ return None class Call: __metaclass__ = abc.ABCMeta @abc.abstractmethod def start_batch(self, ops, tag): """Start a batch of operations. Args: ops (sequence of OpArgs): ... tag (object): ... Returns: CallError: ... """ return CallError.ERROR @abc.abstractmethod def cancel(self, code=None, details=None): """Cancel the call. Args: code (int): Status code to cancel with (on the server side). If specified, so must `details`. details (str): Status details to cancel with (on the server side). If specified, so must `code`. Returns: CallError: ... """ return CallError.ERROR @abc.abstractmethod def peer(self): """Get the peer of this call. Returns: str: the peer of this call. """ return None class Channel: __metaclass__ = abc.ABCMeta @abc.abstractmethod def __init__(self, target, args, credentials=None): """Initialize a Channel. Args: target (str): ... args (sequence of 2-sequence of str, (str|integer)): ... credentials (ClientCredentials): If None, create an insecure channel, else create a secure channel using the client credentials. """ @abc.abstractmethod def create_call(self, completion_queue, method, host, deadline=float('+inf')): """Create a call from this channel. Args: completion_queue (CompletionQueue): ... method (str): ... host (str): ... deadline (float): absolute deadline in seconds from the Python epoch, or None for no deadline. Returns: Call: call object associated with this Channel and passed parameters. """ return None @abc.abstractmethod def check_connectivity_state(self, try_to_connect): """Check and optionally repair the connectivity state of the channel. Args: try_to_connect (bool): whether or not to try to connect the channel if disconnected. Returns: ConnectivityState: state of the channel at the time of this invocation. """ return None @abc.abstractmethod def watch_connectivity_state(self, last_observed_state, deadline, completion_queue, tag): """Watch for connectivity state changes from the last_observed_state. Args: last_observed_state (ConnectivityState): ... deadline (float): ... completion_queue (CompletionQueue): ... tag (object) ... """ @abc.abstractmethod def target(self): """Get the target of this channel. Returns: str: the target of this channel. """ return None class Server: __metaclass__ = abc.ABCMeta @abc.abstractmethod def __init__(self, completion_queue, args): """Initialize a server. Args: completion_queue (CompletionQueue): ... args (sequence of 2-sequence of str, (str|integer)): ... """ @abc.abstractmethod def add_http2_port(self, address, credentials=None): """Adds an HTTP/2 address+port to the server. Args: address (str): ... credentials (ServerCredentials): If None, create an insecure port, else create a secure port using the server credentials. """ @abc.abstractmethod def start(self): """Starts the server.""" @abc.abstractmethod def shutdown(self, tag=None): """Shuts down the server. Does not immediately destroy the server. Args: tag (object): if not None, have the server place an event on its completion queue notifying it when this server has completely shut down. """ @abc.abstractmethod def request_call(self, completion_queue, tag): """Requests a call from the server on the server's completion queue. Args: completion_queue (CompletionQueue): Completion queue for the call. May be the same as the server's completion queue. tag (object) ... """ grpc-0.11.1/src/python/grpcio/grpc/_adapter/__init__.py0000644000175000017500000000277212600663151023145 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/0000755000175000017500000000000012600663151021405 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types.h0000644000175000017500000002561612600663151022734 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC__ADAPTER__C_TYPES_H_ #define GRPC__ADAPTER__C_TYPES_H_ #define PY_SSIZE_T_CLEAN #include #include #include /*=========================*/ /* Client-side credentials */ /*=========================*/ typedef struct ClientCredentials { PyObject_HEAD grpc_credentials *c_creds; } ClientCredentials; void pygrpc_ClientCredentials_dealloc(ClientCredentials *self); ClientCredentials *pygrpc_ClientCredentials_google_default( PyTypeObject *type, PyObject *ignored); ClientCredentials *pygrpc_ClientCredentials_ssl( PyTypeObject *type, PyObject *args, PyObject *kwargs); ClientCredentials *pygrpc_ClientCredentials_composite( PyTypeObject *type, PyObject *args, PyObject *kwargs); ClientCredentials *pygrpc_ClientCredentials_compute_engine( PyTypeObject *type, PyObject *ignored); ClientCredentials *pygrpc_ClientCredentials_jwt( PyTypeObject *type, PyObject *args, PyObject *kwargs); ClientCredentials *pygrpc_ClientCredentials_refresh_token( PyTypeObject *type, PyObject *args, PyObject *kwargs); ClientCredentials *pygrpc_ClientCredentials_iam( PyTypeObject *type, PyObject *args, PyObject *kwargs); extern PyTypeObject pygrpc_ClientCredentials_type; /*=========================*/ /* Server-side credentials */ /*=========================*/ typedef struct ServerCredentials { PyObject_HEAD grpc_server_credentials *c_creds; } ServerCredentials; void pygrpc_ServerCredentials_dealloc(ServerCredentials *self); ServerCredentials *pygrpc_ServerCredentials_ssl( PyTypeObject *type, PyObject *args, PyObject *kwargs); extern PyTypeObject pygrpc_ServerCredentials_type; /*==================*/ /* Completion queue */ /*==================*/ typedef struct CompletionQueue { PyObject_HEAD grpc_completion_queue *c_cq; } CompletionQueue; CompletionQueue *pygrpc_CompletionQueue_new( PyTypeObject *type, PyObject *args, PyObject *kwargs); void pygrpc_CompletionQueue_dealloc(CompletionQueue *self); PyObject *pygrpc_CompletionQueue_next( CompletionQueue *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_CompletionQueue_shutdown( CompletionQueue *self, PyObject *ignored); extern PyTypeObject pygrpc_CompletionQueue_type; /*======*/ /* Call */ /*======*/ typedef struct Call { PyObject_HEAD grpc_call *c_call; CompletionQueue *cq; } Call; Call *pygrpc_Call_new_empty(CompletionQueue *cq); void pygrpc_Call_dealloc(Call *self); PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Call_peer(Call *self); PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args, PyObject *kwargs); extern PyTypeObject pygrpc_Call_type; /*=========*/ /* Channel */ /*=========*/ typedef struct Channel { PyObject_HEAD grpc_channel *c_chan; } Channel; Channel *pygrpc_Channel_new( PyTypeObject *type, PyObject *args, PyObject *kwargs); void pygrpc_Channel_dealloc(Channel *self); Call *pygrpc_Channel_create_call( Channel *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Channel_check_connectivity_state(Channel *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Channel_watch_connectivity_state(Channel *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Channel_target(Channel *self); extern PyTypeObject pygrpc_Channel_type; /*========*/ /* Server */ /*========*/ typedef struct Server { PyObject_HEAD grpc_server *c_serv; CompletionQueue *cq; int shutdown_called; } Server; Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs); void pygrpc_Server_dealloc(Server *self); PyObject *pygrpc_Server_request_call( Server *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Server_add_http2_port( Server *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Server_start(Server *self, PyObject *ignored); PyObject *pygrpc_Server_shutdown( Server *self, PyObject *args, PyObject *kwargs); PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused); extern PyTypeObject pygrpc_Server_type; /*=========*/ /* Utility */ /*=========*/ /* Every tag that passes from Python GRPC to GRPC core is of this type. */ typedef struct pygrpc_tag { PyObject *user_tag; Call *call; grpc_call_details request_call_details; grpc_metadata_array request_metadata; grpc_op *ops; size_t nops; int is_new_call; } pygrpc_tag; /* Construct a tag associated with a batch call. Does not take ownership of the resources in the elements of ops. */ pygrpc_tag *pygrpc_produce_batch_tag(PyObject *user_tag, Call *call, grpc_op *ops, size_t nops); /* Construct a tag associated with a server request. The calling code should use the appropriate fields of the produced tag in the invocation of grpc_server_request_call. */ pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call); /* Construct a tag associated with a server shutdown. */ pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag); /* Construct a tag associated with a channel state change. */ pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag); /* Frees all resources owned by the tag and the tag itself. */ void pygrpc_discard_tag(pygrpc_tag *tag); /* Consumes an event and its associated tag, providing a Python tuple of the form `(type, tag, call, call_details, results)` (where type is an integer corresponding to a grpc_completion_type, tag is an arbitrary PyObject, call is the call object associated with the event [if any], call_details is a tuple of form `(method, host, deadline)` [if such details are available], and resultd is a list of tuples of form `(type, metadata, message, status, cancelled)` [where type corresponds to a grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a byte string, and status is a 2-tuple of an integer corresponding to grpc_status_code and a string of status details]). Frees all resources associated with the event tag. */ PyObject *pygrpc_consume_event(grpc_event event); /* Transliterate the Python tuple of form `(type, metadata, message, status)` (where type is an integer corresponding to a grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a byte string, and status is 2-tuple of an integer corresponding to grpc_status_code and a string of status details) to a grpc_op suitable for use in a grpc_call_start_batch invocation. The grpc_op is a 'directory' of resources that must be freed after GRPC core is done with them. Calls gpr_malloc (or the appropriate type-specific grpc_*_create function) to populate the appropriate union-discriminated members of the op. Returns true on success, false on failure. */ int pygrpc_produce_op(PyObject *op, grpc_op *result); /* Discards all resources associated with the passed in op that was produced by pygrpc_produce_op. */ void pygrpc_discard_op(grpc_op op); /* Transliterate the grpc_ops (which have been sent through a grpc_call_start_batch invocation and whose corresponding event has appeared on a completion queue) to a Python tuple of form `(type, metadata, message, status, cancelled)` (where type is an integer corresponding to a grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a byte string, and status is 2-tuple of an integer corresponding to grpc_status_code and a string of status details). Calls gpr_free (or the appropriate type-specific grpc_*_destroy function) on the appropriate union-discriminated populated members of the ops. */ PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops); /* Transliterate from a gpr_timespec to a double (in units of seconds, either from the epoch if interpreted absolutely or as a delta otherwise). */ double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec); /* Transliterate from a double (in units of seconds from the epoch if interpreted absolutely or as a delta otherwise) to a gpr_timespec. */ gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds); /* Returns true on success, false on failure. */ int pygrpc_cast_pyseq_to_send_metadata( PyObject *pyseq, grpc_metadata **metadata, size_t *count); /* Returns a metadata array as a Python object on success, else NULL. */ PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata); /* Transliterate from a list of python channel arguments (2-tuples of string and string|integer|None) to a grpc_channel_args object. The strings placed in the grpc_channel_args object's grpc_arg elements are views of the Python object. The Python object must live long enough for the grpc_channel_args to be used. Arguments set to None are silently ignored. Returns true on success, false on failure. */ int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args); void pygrpc_discard_channel_args(grpc_channel_args args); /* Read the bytes from grpc_byte_buffer to a gpr_malloc'd array of bytes; output to result and result_size. */ void pygrpc_byte_buffer_to_bytes( grpc_byte_buffer *buffer, char **result, size_t *result_size); /*========*/ /* Module */ /*========*/ /* Returns 0 on success, -1 on failure. */ int pygrpc_module_add_types(PyObject *module); #endif /* GRPC__ADAPTER__C_TYPES_H_ */ grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/utility.c0000644000175000017500000004364412600663151023267 0ustar apollockapollock/* * * 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 #include #define PY_SSIZE_T_CLEAN #include #include #include #include #include #include #include #include "grpc/_adapter/_c/types.h" pygrpc_tag *pygrpc_produce_batch_tag( PyObject *user_tag, Call *call, grpc_op *ops, size_t nops) { pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); tag->user_tag = user_tag; Py_XINCREF(tag->user_tag); tag->call = call; Py_XINCREF(tag->call); tag->ops = gpr_malloc(sizeof(grpc_op)*nops); memcpy(tag->ops, ops, sizeof(grpc_op)*nops); tag->nops = nops; grpc_call_details_init(&tag->request_call_details); grpc_metadata_array_init(&tag->request_metadata); tag->is_new_call = 0; return tag; } pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call) { pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); tag->user_tag = user_tag; Py_XINCREF(tag->user_tag); tag->call = empty_call; Py_XINCREF(tag->call); tag->ops = NULL; tag->nops = 0; grpc_call_details_init(&tag->request_call_details); grpc_metadata_array_init(&tag->request_metadata); tag->is_new_call = 1; return tag; } pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag) { pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); tag->user_tag = user_tag; Py_XINCREF(tag->user_tag); tag->call = NULL; tag->ops = NULL; tag->nops = 0; grpc_call_details_init(&tag->request_call_details); grpc_metadata_array_init(&tag->request_metadata); tag->is_new_call = 0; return tag; } pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag) { pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag)); tag->user_tag = user_tag; Py_XINCREF(tag->user_tag); tag->call = NULL; tag->ops = NULL; tag->nops = 0; grpc_call_details_init(&tag->request_call_details); grpc_metadata_array_init(&tag->request_metadata); tag->is_new_call = 0; return tag; } void pygrpc_discard_tag(pygrpc_tag *tag) { if (!tag) { return; } Py_XDECREF(tag->user_tag); Py_XDECREF(tag->call); gpr_free(tag->ops); grpc_call_details_destroy(&tag->request_call_details); grpc_metadata_array_destroy(&tag->request_metadata); gpr_free(tag); } PyObject *pygrpc_consume_event(grpc_event event) { pygrpc_tag *tag; PyObject *result; if (event.type == GRPC_QUEUE_TIMEOUT) { Py_RETURN_NONE; } tag = event.tag; switch (event.type) { case GRPC_QUEUE_SHUTDOWN: result = Py_BuildValue("iOOOOO", GRPC_QUEUE_SHUTDOWN, Py_None, Py_None, Py_None, Py_None, Py_True); break; case GRPC_OP_COMPLETE: if (tag->is_new_call) { result = Py_BuildValue( "iOO(ssd)[(iNOOOO)]O", GRPC_OP_COMPLETE, tag->user_tag, tag->call, tag->request_call_details.method, tag->request_call_details.host, pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline), GRPC_OP_RECV_INITIAL_METADATA, pygrpc_cast_metadata_array_to_pyseq(tag->request_metadata), Py_None, Py_None, Py_None, Py_None, event.success ? Py_True : Py_False); } else { result = Py_BuildValue("iOOONO", GRPC_OP_COMPLETE, tag->user_tag, tag->call ? (PyObject*)tag->call : Py_None, Py_None, pygrpc_consume_ops(tag->ops, tag->nops), event.success ? Py_True : Py_False); } break; default: PyErr_SetString(PyExc_ValueError, "unknown completion type; could not translate event"); return NULL; } pygrpc_discard_tag(tag); return result; } int pygrpc_produce_op(PyObject *op, grpc_op *result) { static const int OP_TUPLE_SIZE = 6; static const int STATUS_TUPLE_SIZE = 2; static const int TYPE_INDEX = 0; static const int INITIAL_METADATA_INDEX = 1; static const int TRAILING_METADATA_INDEX = 2; static const int MESSAGE_INDEX = 3; static const int STATUS_INDEX = 4; static const int STATUS_CODE_INDEX = 0; static const int STATUS_DETAILS_INDEX = 1; static const int WRITE_FLAGS_INDEX = 5; int type; Py_ssize_t message_size; char *message; char *status_details; gpr_slice message_slice; grpc_op c_op; if (!PyTuple_Check(op)) { PyErr_SetString(PyExc_TypeError, "expected tuple op"); return 0; } if (PyTuple_Size(op) != OP_TUPLE_SIZE) { char *buf; gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE); PyErr_SetString(PyExc_ValueError, buf); gpr_free(buf); return 0; } type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX)); if (PyErr_Occurred()) { return 0; } c_op.op = type; c_op.reserved = NULL; c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX)); if (PyErr_Occurred()) { return 0; } switch (type) { case GRPC_OP_SEND_INITIAL_METADATA: if (!pygrpc_cast_pyseq_to_send_metadata( PyTuple_GetItem(op, INITIAL_METADATA_INDEX), &c_op.data.send_initial_metadata.metadata, &c_op.data.send_initial_metadata.count)) { return 0; } break; case GRPC_OP_SEND_MESSAGE: PyString_AsStringAndSize( PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size); message_slice = gpr_slice_from_copied_buffer(message, message_size); c_op.data.send_message = grpc_raw_byte_buffer_create(&message_slice, 1); gpr_slice_unref(message_slice); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: /* Don't need to fill in any other fields. */ break; case GRPC_OP_SEND_STATUS_FROM_SERVER: if (!pygrpc_cast_pyseq_to_send_metadata( PyTuple_GetItem(op, TRAILING_METADATA_INDEX), &c_op.data.send_status_from_server.trailing_metadata, &c_op.data.send_status_from_server.trailing_metadata_count)) { return 0; } if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) { char *buf; gpr_asprintf(&buf, "expected tuple status in op of length %d", STATUS_TUPLE_SIZE); PyErr_SetString(PyExc_ValueError, buf); gpr_free(buf); return 0; } c_op.data.send_status_from_server.status = PyInt_AsLong( PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX)); status_details = PyString_AsString( PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX)); if (PyErr_Occurred()) { return 0; } c_op.data.send_status_from_server.status_details = gpr_malloc(strlen(status_details) + 1); strcpy((char *)c_op.data.send_status_from_server.status_details, status_details); break; case GRPC_OP_RECV_INITIAL_METADATA: c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array)); grpc_metadata_array_init(c_op.data.recv_initial_metadata); break; case GRPC_OP_RECV_MESSAGE: c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *)); break; case GRPC_OP_RECV_STATUS_ON_CLIENT: c_op.data.recv_status_on_client.trailing_metadata = gpr_malloc(sizeof(grpc_metadata_array)); grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata); c_op.data.recv_status_on_client.status = gpr_malloc(sizeof(grpc_status_code *)); c_op.data.recv_status_on_client.status_details = gpr_malloc(sizeof(char *)); *c_op.data.recv_status_on_client.status_details = NULL; c_op.data.recv_status_on_client.status_details_capacity = gpr_malloc(sizeof(size_t)); *c_op.data.recv_status_on_client.status_details_capacity = 0; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int)); break; default: return 0; } *result = c_op; return 1; } void pygrpc_discard_op(grpc_op op) { size_t i; switch(op.op) { case GRPC_OP_SEND_INITIAL_METADATA: /* Whenever we produce send-metadata, we allocate new strings (to handle arbitrary sequence input as opposed to just lists or just tuples). We thus must free those elements. */ for (i = 0; i < op.data.send_initial_metadata.count; ++i) { gpr_free((void *)op.data.send_initial_metadata.metadata[i].key); gpr_free((void *)op.data.send_initial_metadata.metadata[i].value); } gpr_free(op.data.send_initial_metadata.metadata); break; case GRPC_OP_SEND_MESSAGE: grpc_byte_buffer_destroy(op.data.send_message); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: /* Don't need to free any fields. */ break; case GRPC_OP_SEND_STATUS_FROM_SERVER: /* Whenever we produce send-metadata, we allocate new strings (to handle arbitrary sequence input as opposed to just lists or just tuples). We thus must free those elements. */ for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count; ++i) { gpr_free( (void *)op.data.send_status_from_server.trailing_metadata[i].key); gpr_free( (void *)op.data.send_status_from_server.trailing_metadata[i].value); } gpr_free(op.data.send_status_from_server.trailing_metadata); gpr_free((char *)op.data.send_status_from_server.status_details); break; case GRPC_OP_RECV_INITIAL_METADATA: grpc_metadata_array_destroy(op.data.recv_initial_metadata); gpr_free(op.data.recv_initial_metadata); break; case GRPC_OP_RECV_MESSAGE: grpc_byte_buffer_destroy(*op.data.recv_message); gpr_free(op.data.recv_message); break; case GRPC_OP_RECV_STATUS_ON_CLIENT: grpc_metadata_array_destroy(op.data.recv_status_on_client.trailing_metadata); gpr_free(op.data.recv_status_on_client.trailing_metadata); gpr_free(op.data.recv_status_on_client.status); gpr_free(*op.data.recv_status_on_client.status_details); gpr_free(op.data.recv_status_on_client.status_details); gpr_free(op.data.recv_status_on_client.status_details_capacity); break; case GRPC_OP_RECV_CLOSE_ON_SERVER: gpr_free(op.data.recv_close_on_server.cancelled); break; } } PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) { static const int TYPE_INDEX = 0; static const int INITIAL_METADATA_INDEX = 1; static const int TRAILING_METADATA_INDEX = 2; static const int MESSAGE_INDEX = 3; static const int STATUS_INDEX = 4; static const int CANCELLED_INDEX = 5; static const int OPRESULT_LENGTH = 6; PyObject *list; size_t i; size_t j; char *bytes; size_t bytes_size; PyObject *results = PyList_New(nops); if (!results) { return NULL; } for (i = 0; i < nops; ++i) { PyObject *result = PyTuple_Pack(OPRESULT_LENGTH, Py_None, Py_None, Py_None, Py_None, Py_None, Py_None); PyTuple_SetItem(result, TYPE_INDEX, PyInt_FromLong(op[i].op)); switch(op[i].op) { case GRPC_OP_RECV_INITIAL_METADATA: PyTuple_SetItem(result, INITIAL_METADATA_INDEX, list=PyList_New(op[i].data.recv_initial_metadata->count)); for (j = 0; j < op[i].data.recv_initial_metadata->count; ++j) { grpc_metadata md = op[i].data.recv_initial_metadata->metadata[j]; PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value, (Py_ssize_t)md.value_length)); } break; case GRPC_OP_RECV_MESSAGE: if (*op[i].data.recv_message) { pygrpc_byte_buffer_to_bytes( *op[i].data.recv_message, &bytes, &bytes_size); PyTuple_SetItem(result, MESSAGE_INDEX, PyString_FromStringAndSize(bytes, bytes_size)); gpr_free(bytes); } else { PyTuple_SetItem(result, MESSAGE_INDEX, Py_BuildValue("")); } break; case GRPC_OP_RECV_STATUS_ON_CLIENT: PyTuple_SetItem( result, TRAILING_METADATA_INDEX, list = PyList_New(op[i].data.recv_status_on_client.trailing_metadata->count)); for (j = 0; j < op[i].data.recv_status_on_client.trailing_metadata->count; ++j) { grpc_metadata md = op[i].data.recv_status_on_client.trailing_metadata->metadata[j]; PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value, (Py_ssize_t)md.value_length)); } PyTuple_SetItem( result, STATUS_INDEX, Py_BuildValue( "is", *op[i].data.recv_status_on_client.status, *op[i].data.recv_status_on_client.status_details)); break; case GRPC_OP_RECV_CLOSE_ON_SERVER: PyTuple_SetItem( result, CANCELLED_INDEX, PyBool_FromLong(*op[i].data.recv_close_on_server.cancelled)); break; default: break; } pygrpc_discard_op(op[i]); PyList_SetItem(results, i, result); } return results; } double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) { timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME); return timespec.tv_sec + 1e-9*timespec.tv_nsec; } /* Because C89 doesn't have a way to check for infinity... */ static int pygrpc_isinf(double x) { return x * 0 != 0; } gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) { gpr_timespec result; if (pygrpc_isinf(seconds)) { result = seconds > 0.0 ? gpr_inf_future(GPR_CLOCK_REALTIME) : gpr_inf_past(GPR_CLOCK_REALTIME); } else { result.tv_sec = (time_t)seconds; result.tv_nsec = ((seconds - result.tv_sec) * 1e9); result.clock_type = GPR_CLOCK_REALTIME; } return result; } int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args) { size_t num_args = PyList_Size(py_args); size_t i; grpc_channel_args args; args.num_args = num_args; args.args = gpr_malloc(sizeof(grpc_arg) * num_args); for (i = 0; i < args.num_args; ++i) { char *key; PyObject *value; if (!PyArg_ParseTuple(PyList_GetItem(py_args, i), "zO", &key, &value)) { gpr_free(args.args); args.num_args = 0; args.args = NULL; PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuple of str and str|int|None"); return 0; } args.args[i].key = key; if (PyInt_Check(value)) { args.args[i].type = GRPC_ARG_INTEGER; args.args[i].value.integer = PyInt_AsLong(value); } else if (PyString_Check(value)) { args.args[i].type = GRPC_ARG_STRING; args.args[i].value.string = PyString_AsString(value); } else if (value == Py_None) { --args.num_args; --i; continue; } else { gpr_free(args.args); args.num_args = 0; args.args = NULL; PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuple of str and str|int|None"); return 0; } } *c_args = args; return 1; } void pygrpc_discard_channel_args(grpc_channel_args args) { gpr_free(args.args); } int pygrpc_cast_pyseq_to_send_metadata( PyObject *pyseq, grpc_metadata **metadata, size_t *count) { size_t i; Py_ssize_t value_length; char *key; char *value; if (!PySequence_Check(pyseq)) { return 0; } *count = PySequence_Size(pyseq); *metadata = gpr_malloc(sizeof(grpc_metadata) * *count); for (i = 0; i < *count; ++i) { PyObject *item = PySequence_GetItem(pyseq, i); if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) { Py_DECREF(item); gpr_free(*metadata); *count = 0; *metadata = NULL; return 0; } else { (*metadata)[i].key = gpr_strdup(key); (*metadata)[i].value = gpr_malloc(value_length); memcpy((void *)(*metadata)[i].value, value, value_length); Py_DECREF(item); } (*metadata)[i].value_length = value_length; } return 1; } PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) { PyObject *result = PyTuple_New(metadata.count); size_t i; for (i = 0; i < metadata.count; ++i) { PyTuple_SetItem( result, i, Py_BuildValue( "ss#", metadata.metadata[i].key, metadata.metadata[i].value, (Py_ssize_t)metadata.metadata[i].value_length)); if (PyErr_Occurred()) { Py_DECREF(result); return NULL; } } return result; } void pygrpc_byte_buffer_to_bytes( grpc_byte_buffer *buffer, char **result, size_t *result_size) { grpc_byte_buffer_reader reader; gpr_slice slice; char *read_result = NULL; size_t size = 0; grpc_byte_buffer_reader_init(&reader, buffer); while (grpc_byte_buffer_reader_next(&reader, &slice)) { read_result = gpr_realloc(read_result, size + GPR_SLICE_LENGTH(slice)); memcpy(read_result + size, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)); size = size + GPR_SLICE_LENGTH(slice); gpr_slice_unref(slice); } *result_size = size; *result = read_result; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types.c0000644000175000017500000000433012600663151022715 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include int pygrpc_module_add_types(PyObject *module) { int i; PyTypeObject *types[] = { &pygrpc_ClientCredentials_type, &pygrpc_ServerCredentials_type, &pygrpc_CompletionQueue_type, &pygrpc_Call_type, &pygrpc_Channel_type, &pygrpc_Server_type }; for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) { if (PyType_Ready(types[i]) < 0) { return -1; } } for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) { Py_INCREF(types[i]); PyModule_AddObject(module, types[i]->tp_name, (PyObject *)types[i]); } return 0; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/0000755000175000017500000000000012600663151022551 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c0000644000175000017500000002361712600663151026561 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include #include PyMethodDef pygrpc_ClientCredentials_methods[] = { {"google_default", (PyCFunction)pygrpc_ClientCredentials_google_default, METH_CLASS|METH_NOARGS, ""}, {"ssl", (PyCFunction)pygrpc_ClientCredentials_ssl, METH_CLASS|METH_KEYWORDS, ""}, {"composite", (PyCFunction)pygrpc_ClientCredentials_composite, METH_CLASS|METH_KEYWORDS, ""}, {"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine, METH_CLASS|METH_NOARGS, ""}, {"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt, METH_CLASS|METH_KEYWORDS, ""}, {"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token, METH_CLASS|METH_KEYWORDS, ""}, {"iam", (PyCFunction)pygrpc_ClientCredentials_iam, METH_CLASS|METH_KEYWORDS, ""}, {NULL} }; const char pygrpc_ClientCredentials_doc[] = ""; PyTypeObject pygrpc_ClientCredentials_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "ClientCredentials", /* tp_name */ sizeof(ClientCredentials), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)pygrpc_ClientCredentials_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ pygrpc_ClientCredentials_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ pygrpc_ClientCredentials_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0 /* tp_new */ }; void pygrpc_ClientCredentials_dealloc(ClientCredentials *self) { grpc_credentials_release(self->c_creds); self->ob_type->tp_free((PyObject *)self); } ClientCredentials *pygrpc_ClientCredentials_google_default( PyTypeObject *type, PyObject *ignored) { ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_default_credentials_create(); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create Google default credentials"); return NULL; } return self; } ClientCredentials *pygrpc_ClientCredentials_ssl( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; const char *root_certs; const char *private_key = NULL; const char *cert_chain = NULL; grpc_ssl_pem_key_cert_pair key_cert_pair; static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords, &root_certs, &private_key, &cert_chain)) { return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); if (private_key && cert_chain) { key_cert_pair.private_key = private_key; key_cert_pair.cert_chain = cert_chain; self->c_creds = grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL); } else { self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL); } if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials"); return NULL; } return self; } ClientCredentials *pygrpc_ClientCredentials_composite( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; ClientCredentials *creds1; ClientCredentials *creds2; static char *keywords[] = {"creds1", "creds2", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords, &pygrpc_ClientCredentials_type, &creds1, &pygrpc_ClientCredentials_type, &creds2)) { return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_composite_credentials_create(creds1->c_creds, creds2->c_creds, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials"); return NULL; } return self; } ClientCredentials *pygrpc_ClientCredentials_compute_engine( PyTypeObject *type, PyObject *ignored) { ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_compute_engine_credentials_create(NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create compute engine credentials"); return NULL; } return self; } /* TODO: Rename this credentials to something like service_account_jwt_access */ ClientCredentials *pygrpc_ClientCredentials_jwt( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; const char *json_key; double lifetime; static char *keywords[] = {"json_key", "token_lifetime", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd:jwt", keywords, &json_key, &lifetime)) { return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_service_account_jwt_access_credentials_create( json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials"); return NULL; } return self; } ClientCredentials *pygrpc_ClientCredentials_refresh_token( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; const char *json_refresh_token; static char *keywords[] = {"json_refresh_token", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords, &json_refresh_token)) { return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_refresh_token_credentials_create(json_refresh_token, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create credentials from refresh token"); return NULL; } return self; } ClientCredentials *pygrpc_ClientCredentials_iam( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; const char *authorization_token; const char *authority_selector; static char *keywords[] = {"authorization_token", "authority_selector", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:iam", keywords, &authorization_token, &authority_selector)) { return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_iam_credentials_create(authorization_token, authority_selector, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials"); return NULL; } return self; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/call.c0000644000175000017500000001666312600663151023644 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include #include PyMethodDef pygrpc_Call_methods[] = { {"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""}, {"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""}, {"peer", (PyCFunction)pygrpc_Call_peer, METH_NOARGS, ""}, {"set_credentials", (PyCFunction)pygrpc_Call_set_credentials, METH_KEYWORDS, ""}, {NULL} }; const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call."; PyTypeObject pygrpc_Call_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "Call", /* tp_name */ sizeof(Call), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)pygrpc_Call_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ pygrpc_Call_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ pygrpc_Call_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0 /* tp_new */ }; Call *pygrpc_Call_new_empty(CompletionQueue *cq) { Call *call = (Call *)pygrpc_Call_type.tp_alloc(&pygrpc_Call_type, 0); call->c_call = NULL; call->cq = cq; Py_XINCREF(call->cq); return call; } void pygrpc_Call_dealloc(Call *self) { if (self->c_call) { grpc_call_destroy(self->c_call); } Py_XDECREF(self->cq); self->ob_type->tp_free((PyObject *)self); } PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs) { PyObject *op_list; PyObject *user_tag; grpc_op *ops; size_t nops; size_t i; size_t j; pygrpc_tag *tag; grpc_call_error errcode; static char *keywords[] = {"ops", "tag", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:start_batch", keywords, &op_list, &user_tag)) { return NULL; } if (!PyList_Check(op_list)) { PyErr_SetString(PyExc_TypeError, "expected a list of OpArgs"); return NULL; } nops = PyList_Size(op_list); ops = gpr_malloc(sizeof(grpc_op) * nops); for (i = 0; i < nops; ++i) { PyObject *item = PyList_GET_ITEM(op_list, i); if (!pygrpc_produce_op(item, &ops[i])) { for (j = 0; j < i; ++j) { pygrpc_discard_op(ops[j]); } return NULL; } } tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops); errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag, NULL); gpr_free(ops); return PyInt_FromLong(errcode); } PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) { PyObject *py_code = NULL; grpc_call_error errcode; int code; char *details = NULL; static char *keywords[] = {"code", "details", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:start_batch", keywords, &py_code, &details)) { return NULL; } if (py_code != NULL && details != NULL) { if (!PyInt_Check(py_code)) { PyErr_SetString(PyExc_TypeError, "expected integer code"); return NULL; } code = PyInt_AsLong(py_code); errcode = grpc_call_cancel_with_status(self->c_call, code, details, NULL); } else if (py_code != NULL || details != NULL) { PyErr_SetString(PyExc_ValueError, "if `code` is specified, so must `details`"); return NULL; } else { errcode = grpc_call_cancel(self->c_call, NULL); } return PyInt_FromLong(errcode); } PyObject *pygrpc_Call_peer(Call *self) { char *peer = grpc_call_get_peer(self->c_call); PyObject *py_peer = PyString_FromString(peer); gpr_free(peer); return py_peer; } PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args, PyObject *kwargs) { ClientCredentials *creds; grpc_call_error errcode; static char *keywords[] = {"creds", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, "O!:set_credentials", keywords, &pygrpc_ClientCredentials_type, &creds)) { return NULL; } errcode = grpc_call_set_credentials(self->c_call, creds->c_creds); return PyInt_FromLong(errcode); } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c0000644000175000017500000001275412600663151026303 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include PyMethodDef pygrpc_CompletionQueue_methods[] = { {"next", (PyCFunction)pygrpc_CompletionQueue_next, METH_KEYWORDS, ""}, {"shutdown", (PyCFunction)pygrpc_CompletionQueue_shutdown, METH_NOARGS, ""}, {NULL} }; const char pygrpc_CompletionQueue_doc[] = "See grpc._adapter._types.CompletionQueue."; PyTypeObject pygrpc_CompletionQueue_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "CompletionQueue", /* tp_name */ sizeof(CompletionQueue), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)pygrpc_CompletionQueue_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ pygrpc_CompletionQueue_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ pygrpc_CompletionQueue_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ (newfunc)pygrpc_CompletionQueue_new /* tp_new */ }; CompletionQueue *pygrpc_CompletionQueue_new( PyTypeObject *type, PyObject *args, PyObject *kwargs) { CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0); self->c_cq = grpc_completion_queue_create(NULL); return self; } void pygrpc_CompletionQueue_dealloc(CompletionQueue *self) { grpc_completion_queue_destroy(self->c_cq); self->ob_type->tp_free((PyObject *)self); } PyObject *pygrpc_CompletionQueue_next( CompletionQueue *self, PyObject *args, PyObject *kwargs) { double deadline; grpc_event event; PyObject *transliterated_event; static char *keywords[] = {"deadline", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:next", keywords, &deadline)) { return NULL; } Py_BEGIN_ALLOW_THREADS; event = grpc_completion_queue_next( self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline), NULL); Py_END_ALLOW_THREADS; transliterated_event = pygrpc_consume_event(event); return transliterated_event; } PyObject *pygrpc_CompletionQueue_shutdown( CompletionQueue *self, PyObject *ignored) { grpc_completion_queue_shutdown(self->c_cq); Py_RETURN_NONE; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/channel.c0000644000175000017500000001740512600663151024334 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include #include PyMethodDef pygrpc_Channel_methods[] = { {"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""}, {"check_connectivity_state", (PyCFunction)pygrpc_Channel_check_connectivity_state, METH_KEYWORDS, ""}, {"watch_connectivity_state", (PyCFunction)pygrpc_Channel_watch_connectivity_state, METH_KEYWORDS, ""}, {"target", (PyCFunction)pygrpc_Channel_target, METH_NOARGS, ""}, {NULL} }; const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel."; PyTypeObject pygrpc_Channel_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "Channel", /* tp_name */ sizeof(Channel), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)pygrpc_Channel_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ pygrpc_Channel_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ pygrpc_Channel_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ (newfunc)pygrpc_Channel_new /* tp_new */ }; Channel *pygrpc_Channel_new( PyTypeObject *type, PyObject *args, PyObject *kwargs) { Channel *self; const char *target; PyObject *py_args; ClientCredentials *creds = NULL; grpc_channel_args c_args; char *keywords[] = {"target", "args", "creds", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords, &target, &py_args, &pygrpc_ClientCredentials_type, &creds)) { return NULL; } if (!pygrpc_produce_channel_args(py_args, &c_args)) { return NULL; } self = (Channel *)type->tp_alloc(type, 0); if (creds) { self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args, NULL); } else { self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL); } pygrpc_discard_channel_args(c_args); return self; } void pygrpc_Channel_dealloc(Channel *self) { grpc_channel_destroy(self->c_chan); self->ob_type->tp_free((PyObject *)self); } Call *pygrpc_Channel_create_call( Channel *self, PyObject *args, PyObject *kwargs) { Call *call; CompletionQueue *cq; const char *method; const char *host; double deadline; char *keywords[] = {"cq", "method", "host", "deadline", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!szd:create_call", keywords, &pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) { return NULL; } call = pygrpc_Call_new_empty(cq); call->c_call = grpc_channel_create_call( self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host, pygrpc_cast_double_to_gpr_timespec(deadline), NULL); return call; } PyObject *pygrpc_Channel_check_connectivity_state( Channel *self, PyObject *args, PyObject *kwargs) { PyObject *py_try_to_connect; int try_to_connect; char *keywords[] = {"try_to_connect", NULL}; grpc_connectivity_state state; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:connectivity_state", keywords, &py_try_to_connect)) { return NULL; } if (!PyBool_Check(py_try_to_connect)) { Py_XDECREF(py_try_to_connect); return NULL; } try_to_connect = Py_True == py_try_to_connect; Py_DECREF(py_try_to_connect); state = grpc_channel_check_connectivity_state(self->c_chan, try_to_connect); return PyInt_FromLong(state); } PyObject *pygrpc_Channel_watch_connectivity_state( Channel *self, PyObject *args, PyObject *kwargs) { PyObject *tag; double deadline; int last_observed_state; CompletionQueue *completion_queue; char *keywords[] = {"last_observed_state", "deadline", "completion_queue", "tag", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, "idO!O:watch_connectivity_state", keywords, &last_observed_state, &deadline, &pygrpc_CompletionQueue_type, &completion_queue, &tag)) { return NULL; } grpc_channel_watch_connectivity_state( self->c_chan, (grpc_connectivity_state)last_observed_state, pygrpc_cast_double_to_gpr_timespec(deadline), completion_queue->c_cq, pygrpc_produce_channel_state_change_tag(tag)); Py_RETURN_NONE; } PyObject *pygrpc_Channel_target(Channel *self) { char *target = grpc_channel_get_target(self->c_chan); PyObject *py_target = PyString_FromString(target); gpr_free(target); return py_target; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/server.c0000644000175000017500000001720012600663151024223 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include PyMethodDef pygrpc_Server_methods[] = { {"request_call", (PyCFunction)pygrpc_Server_request_call, METH_KEYWORDS, ""}, {"add_http2_port", (PyCFunction)pygrpc_Server_add_http2_port, METH_KEYWORDS, ""}, {"start", (PyCFunction)pygrpc_Server_start, METH_NOARGS, ""}, {"shutdown", (PyCFunction)pygrpc_Server_shutdown, METH_KEYWORDS, ""}, {"cancel_all_calls", (PyCFunction)pygrpc_Server_cancel_all_calls, METH_NOARGS, ""}, {NULL} }; const char pygrpc_Server_doc[] = "See grpc._adapter._types.Server."; PyTypeObject pygrpc_Server_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "Server", /* tp_name */ sizeof(Server), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)pygrpc_Server_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ pygrpc_Server_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ pygrpc_Server_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ (newfunc)pygrpc_Server_new /* tp_new */ }; Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { Server *self; CompletionQueue *cq; PyObject *py_args; grpc_channel_args c_args; char *keywords[] = {"cq", "args", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Server", keywords, &pygrpc_CompletionQueue_type, &cq, &py_args)) { return NULL; } if (!pygrpc_produce_channel_args(py_args, &c_args)) { return NULL; } self = (Server *)type->tp_alloc(type, 0); self->c_serv = grpc_server_create(&c_args, NULL); grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL); pygrpc_discard_channel_args(c_args); self->cq = cq; Py_INCREF(self->cq); self->shutdown_called = 0; return self; } void pygrpc_Server_dealloc(Server *self) { grpc_server_destroy(self->c_serv); Py_XDECREF(self->cq); self->ob_type->tp_free((PyObject *)self); } PyObject *pygrpc_Server_request_call( Server *self, PyObject *args, PyObject *kwargs) { CompletionQueue *cq; PyObject *user_tag; pygrpc_tag *tag; Call *empty_call; grpc_call_error errcode; static char *keywords[] = {"cq", "tag", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, "O!O", keywords, &pygrpc_CompletionQueue_type, &cq, &user_tag)) { return NULL; } empty_call = pygrpc_Call_new_empty(cq); tag = pygrpc_produce_request_tag(user_tag, empty_call); errcode = grpc_server_request_call( self->c_serv, &tag->call->c_call, &tag->request_call_details, &tag->request_metadata, tag->call->cq->c_cq, self->cq->c_cq, tag); Py_DECREF(empty_call); return PyInt_FromLong(errcode); } PyObject *pygrpc_Server_add_http2_port( Server *self, PyObject *args, PyObject *kwargs) { const char *addr; ServerCredentials *creds = NULL; int port; static char *keywords[] = {"addr", "creds", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, "s|O!:add_http2_port", keywords, &addr, &pygrpc_ServerCredentials_type, &creds)) { return NULL; } if (creds) { port = grpc_server_add_secure_http2_port( self->c_serv, addr, creds->c_creds); } else { port = grpc_server_add_insecure_http2_port(self->c_serv, addr); } return PyInt_FromLong(port); } PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) { grpc_server_start(self->c_serv); self->shutdown_called = 0; Py_RETURN_NONE; } PyObject *pygrpc_Server_shutdown( Server *self, PyObject *args, PyObject *kwargs) { PyObject *user_tag; pygrpc_tag *tag; static char *keywords[] = {"tag", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &user_tag)) { return NULL; } tag = pygrpc_produce_server_shutdown_tag(user_tag); grpc_server_shutdown_and_notify(self->c_serv, self->cq->c_cq, tag); self->shutdown_called = 1; Py_RETURN_NONE; } PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused) { if (!self->shutdown_called) { PyErr_SetString( PyExc_RuntimeError, "shutdown must have been called prior to calling cancel_all_calls!"); return NULL; } grpc_server_cancel_all_calls(self->c_serv); Py_RETURN_NONE; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c0000644000175000017500000001372212600663151026605 0ustar apollockapollock/* * * 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 "grpc/_adapter/_c/types.h" #define PY_SSIZE_T_CLEAN #include #include #include #include PyMethodDef pygrpc_ServerCredentials_methods[] = { {"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl, METH_CLASS|METH_KEYWORDS, ""}, {NULL} }; const char pygrpc_ServerCredentials_doc[] = ""; PyTypeObject pygrpc_ServerCredentials_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "ServerCredentials", /* tp_name */ sizeof(ServerCredentials), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)pygrpc_ServerCredentials_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ pygrpc_ServerCredentials_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ pygrpc_ServerCredentials_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0 /* tp_new */ }; void pygrpc_ServerCredentials_dealloc(ServerCredentials *self) { grpc_server_credentials_release(self->c_creds); self->ob_type->tp_free((PyObject *)self); } ServerCredentials *pygrpc_ServerCredentials_ssl( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ServerCredentials *self; const char *root_certs; PyObject *py_key_cert_pairs; grpc_ssl_pem_key_cert_pair *key_cert_pairs; int force_client_auth; size_t num_key_cert_pairs; size_t i; static char *keywords[] = { "root_certs", "key_cert_pairs", "force_client_auth", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zOi:ssl", keywords, &root_certs, &py_key_cert_pairs, &force_client_auth)) { return NULL; } if (!PyList_Check(py_key_cert_pairs)) { PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings"); return NULL; } num_key_cert_pairs = PyList_Size(py_key_cert_pairs); key_cert_pairs = gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs); for (i = 0; i < num_key_cert_pairs; ++i) { PyObject *item = PyList_GET_ITEM(py_key_cert_pairs, i); const char *key; const char *cert; if (!PyArg_ParseTuple(item, "zz", &key, &cert)) { gpr_free(key_cert_pairs); PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings"); return NULL; } key_cert_pairs[i].private_key = key; key_cert_pairs[i].cert_chain = cert; } self = (ServerCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_ssl_server_credentials_create( root_certs, key_cert_pairs, num_key_cert_pairs, force_client_auth, NULL); gpr_free(key_cert_pairs); return self; } grpc-0.11.1/src/python/grpcio/grpc/_adapter/_c/module.c0000644000175000017500000000445012600663151023041 0ustar apollockapollock/* * * 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 #define PY_SSIZE_T_CLEAN #include #include #include "grpc/_adapter/_c/types.h" static PyMethodDef c_methods[] = { {NULL} }; PyMODINIT_FUNC init_c(void) { PyObject *module; module = Py_InitModule3("_c", c_methods, "Wrappings of C structures and functions."); if (pygrpc_module_add_types(module) < 0) { return; } if (PyModule_AddStringConstant( module, "PRIMARY_USER_AGENT_KEY", GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) { return; } /* GRPC maintains an internal counter of how many times it has been initialized and handles multiple pairs of grpc_init()/grpc_shutdown() invocations accordingly. */ grpc_init(); atexit(&grpc_shutdown); } grpc-0.11.1/src/python/grpcio/grpc/_adapter/rear.py0000644000175000017500000003704012600663151022333 0ustar apollockapollock# 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. """The RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire.""" import enum import logging import threading import time from grpc._adapter import _common from grpc._adapter import _intermediary_low as _low from grpc.framework.base import interfaces as base_interfaces from grpc.framework.base import null from grpc.framework.foundation import activated from grpc.framework.foundation import logging_pool _THREAD_POOL_SIZE = 10 _INVOCATION_EVENT_KINDS = ( _low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH ) @enum.unique class _LowWrite(enum.Enum): """The possible categories of low-level write state.""" OPEN = 'OPEN' ACTIVE = 'ACTIVE' CLOSED = 'CLOSED' class _RPCState(object): """The full state of any tracked RPC. Attributes: call: The _low.Call object for the RPC. outstanding: The set of Event.Kind values describing expected future events for the RPC. active: A boolean indicating whether or not the RPC is active. common: An _common.RPCState describing additional state for the RPC. """ def __init__(self, call, outstanding, active, common): self.call = call self.outstanding = outstanding self.active = active self.common = common def _write(operation_id, call, outstanding, write_state, serialized_payload): if write_state.low is _LowWrite.OPEN: call.write(serialized_payload, operation_id, 0) outstanding.add(_low.Event.Kind.WRITE_ACCEPTED) write_state.low = _LowWrite.ACTIVE elif write_state.low is _LowWrite.ACTIVE: write_state.pending.append(serialized_payload) else: raise ValueError('Write attempted after writes completed!') class RearLink(base_interfaces.RearLink, activated.Activated): """An invocation-side bridge between RPC Framework and the C-ish _low code.""" def __init__( self, host, port, pool, request_serializers, response_deserializers, secure, root_certificates, private_key, certificate_chain, metadata_transformer=None, server_host_override=None): """Constructor. Args: host: The host to which to connect for RPC service. port: The port to which to connect for RPC service. pool: A thread pool. request_serializers: A dict from RPC method names to request object serializer behaviors. response_deserializers: A dict from RPC method names to response object deserializer behaviors. secure: A boolean indicating whether or not to use a secure connection. root_certificates: The PEM-encoded root certificates or None to ask for them to be retrieved from a default location. private_key: The PEM-encoded private key to use or None if no private key should be used. certificate_chain: The PEM-encoded certificate chain to use or None if no certificate chain should be used. metadata_transformer: A function that given a metadata object produces another metadata to be used in the underlying communication on the wire. server_host_override: (For testing only) the target name used for SSL host name checking. """ self._condition = threading.Condition() self._host = host self._port = port self._pool = pool self._request_serializers = request_serializers self._response_deserializers = response_deserializers self._fore_link = null.NULL_FORE_LINK self._completion_queue = None self._channel = None self._rpc_states = {} self._spinning = False if secure: self._client_credentials = _low.ClientCredentials( root_certificates, private_key, certificate_chain) else: self._client_credentials = None self._root_certificates = root_certificates self._private_key = private_key self._certificate_chain = certificate_chain self._metadata_transformer = metadata_transformer self._server_host_override = server_host_override def _on_write_event(self, operation_id, event, rpc_state): if event.write_accepted: if rpc_state.common.write.pending: rpc_state.call.write( rpc_state.common.write.pending.pop(0), operation_id, 0) rpc_state.outstanding.add(_low.Event.Kind.WRITE_ACCEPTED) elif rpc_state.common.write.high is _common.HighWrite.CLOSED: rpc_state.call.complete(operation_id) rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED) rpc_state.common.write.low = _LowWrite.CLOSED else: rpc_state.common.write.low = _LowWrite.OPEN else: logging.error('RPC write not accepted! Event: %s', (event,)) rpc_state.active = False ticket = base_interfaces.BackToFrontTicket( operation_id, rpc_state.common.sequence_number, base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None) rpc_state.common.sequence_number += 1 self._fore_link.accept_back_to_front_ticket(ticket) def _on_read_event(self, operation_id, event, rpc_state): if event.bytes is not None: rpc_state.call.read(operation_id) rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED) ticket = base_interfaces.BackToFrontTicket( operation_id, rpc_state.common.sequence_number, base_interfaces.BackToFrontTicket.Kind.CONTINUATION, rpc_state.common.deserializer(event.bytes)) rpc_state.common.sequence_number += 1 self._fore_link.accept_back_to_front_ticket(ticket) def _on_complete_event(self, operation_id, event, rpc_state): if not event.complete_accepted: logging.error('RPC complete not accepted! Event: %s', (event,)) rpc_state.active = False ticket = base_interfaces.BackToFrontTicket( operation_id, rpc_state.common.sequence_number, base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None) rpc_state.common.sequence_number += 1 self._fore_link.accept_back_to_front_ticket(ticket) # TODO(nathaniel): Metadata support. def _on_metadata_event(self, operation_id, event, rpc_state): # pylint: disable=unused-argument rpc_state.call.read(operation_id) rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED) def _on_finish_event(self, operation_id, event, rpc_state): """Handle termination of an RPC.""" # TODO(nathaniel): Cover all statuses. if event.status.code is _low.Code.OK: kind = base_interfaces.BackToFrontTicket.Kind.COMPLETION elif event.status.code is _low.Code.CANCELLED: kind = base_interfaces.BackToFrontTicket.Kind.CANCELLATION elif event.status.code is _low.Code.DEADLINE_EXCEEDED: kind = base_interfaces.BackToFrontTicket.Kind.EXPIRATION else: kind = base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE ticket = base_interfaces.BackToFrontTicket( operation_id, rpc_state.common.sequence_number, kind, None) rpc_state.common.sequence_number += 1 self._fore_link.accept_back_to_front_ticket(ticket) def _spin(self, completion_queue): while True: event = completion_queue.get(None) operation_id = event.tag with self._condition: rpc_state = self._rpc_states[operation_id] rpc_state.outstanding.remove(event.kind) if rpc_state.active and self._completion_queue is not None: if event.kind is _low.Event.Kind.WRITE_ACCEPTED: self._on_write_event(operation_id, event, rpc_state) elif event.kind is _low.Event.Kind.METADATA_ACCEPTED: self._on_metadata_event(operation_id, event, rpc_state) elif event.kind is _low.Event.Kind.READ_ACCEPTED: self._on_read_event(operation_id, event, rpc_state) elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED: self._on_complete_event(operation_id, event, rpc_state) elif event.kind is _low.Event.Kind.FINISH: self._on_finish_event(operation_id, event, rpc_state) else: logging.error('Illegal RPC event! %s', (event,)) if not rpc_state.outstanding: self._rpc_states.pop(operation_id) if not self._rpc_states: self._spinning = False self._condition.notify_all() return def _invoke(self, operation_id, name, high_state, payload, timeout): """Invoke an RPC. Args: operation_id: Any object to be used as an operation ID for the RPC. name: The RPC method name. high_state: A _common.HighWrite value representing the "high write state" of the RPC. payload: A payload object for the RPC or None if no payload was given at invocation-time. timeout: A duration of time in seconds to allow for the RPC. """ request_serializer = self._request_serializers[name] call = _low.Call(self._channel, self._completion_queue, name, self._host, time.time() + timeout) if self._metadata_transformer is not None: metadata = self._metadata_transformer([]) for metadata_key, metadata_value in metadata: call.add_metadata(metadata_key, metadata_value) call.invoke(self._completion_queue, operation_id, operation_id) outstanding = set(_INVOCATION_EVENT_KINDS) if payload is None: if high_state is _common.HighWrite.CLOSED: call.complete(operation_id) low_state = _LowWrite.CLOSED outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED) else: low_state = _LowWrite.OPEN else: serialized_payload = request_serializer(payload) call.write(serialized_payload, operation_id, 0) outstanding.add(_low.Event.Kind.WRITE_ACCEPTED) low_state = _LowWrite.ACTIVE write_state = _common.WriteState(low_state, high_state, []) common_state = _common.CommonRPCState( write_state, 0, self._response_deserializers[name], request_serializer) self._rpc_states[operation_id] = _RPCState( call, outstanding, True, common_state) if not self._spinning: self._pool.submit(self._spin, self._completion_queue) self._spinning = True def _commence(self, operation_id, name, payload, timeout): self._invoke(operation_id, name, _common.HighWrite.OPEN, payload, timeout) def _continue(self, operation_id, payload): rpc_state = self._rpc_states.get(operation_id, None) if rpc_state is None or not rpc_state.active: return _write( operation_id, rpc_state.call, rpc_state.outstanding, rpc_state.common.write, rpc_state.common.serializer(payload)) def _complete(self, operation_id, payload): """Close writes associated with an ongoing RPC. Args: operation_id: Any object being use as an operation ID for the RPC. payload: A payload object for the RPC (and thus the last payload object for the RPC) or None if no payload was given along with the instruction to indicate the end of writes for the RPC. """ rpc_state = self._rpc_states.get(operation_id, None) if rpc_state is None or not rpc_state.active: return write_state = rpc_state.common.write if payload is None: if write_state.low is _LowWrite.OPEN: rpc_state.call.complete(operation_id) rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED) write_state.low = _LowWrite.CLOSED else: _write( operation_id, rpc_state.call, rpc_state.outstanding, write_state, rpc_state.common.serializer(payload)) write_state.high = _common.HighWrite.CLOSED def _entire(self, operation_id, name, payload, timeout): self._invoke(operation_id, name, _common.HighWrite.CLOSED, payload, timeout) def _cancel(self, operation_id): rpc_state = self._rpc_states.get(operation_id, None) if rpc_state is not None and rpc_state.active: rpc_state.call.cancel() rpc_state.active = False def join_fore_link(self, fore_link): """See base_interfaces.RearLink.join_fore_link for specification.""" with self._condition: self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link def _start(self): """Starts this RearLink. This method must be called before attempting to exchange tickets with this object. """ with self._condition: self._completion_queue = _low.CompletionQueue() self._channel = _low.Channel( '%s:%d' % (self._host, self._port), self._client_credentials, server_host_override=self._server_host_override) return self def _stop(self): """Stops this RearLink. This method must be called for proper termination of this object, and no attempts to exchange tickets with this object may be made after this method has been called. """ with self._condition: self._completion_queue.stop() self._completion_queue = None while self._spinning: self._condition.wait() def __enter__(self): """See activated.Activated.__enter__ for specification.""" return self._start() def __exit__(self, exc_type, exc_val, exc_tb): """See activated.Activated.__exit__ for specification.""" self._stop() return False def start(self): """See activated.Activated.start for specification.""" return self._start() def stop(self): """See activated.Activated.stop for specification.""" self._stop() def accept_front_to_back_ticket(self, ticket): """See base_interfaces.RearLink.accept_front_to_back_ticket for spec.""" with self._condition: if self._completion_queue is None: return if ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT: self._commence( ticket.operation_id, ticket.name, ticket.payload, ticket.timeout) elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CONTINUATION: self._continue(ticket.operation_id, ticket.payload) elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMPLETION: self._complete(ticket.operation_id, ticket.payload) elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.ENTIRE: self._entire( ticket.operation_id, ticket.name, ticket.payload, ticket.timeout) elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CANCELLATION: self._cancel(ticket.operation_id) else: # NOTE(nathaniel): All other categories are treated as cancellation. self._cancel(ticket.operation_id) grpc-0.11.1/src/python/grpcio/grpc/_adapter/.gitignore0000644000175000017500000000003312600663151023010 0ustar apollockapollock*.a *.so *.dll *.pyc *.pyd grpc-0.11.1/src/python/grpcio/grpc/_adapter/_low.py0000644000175000017500000001105312600663151022336 0ustar apollockapollock# 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. from grpc import _grpcio_metadata from grpc._adapter import _c from grpc._adapter import _types _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__) ClientCredentials = _c.ClientCredentials ServerCredentials = _c.ServerCredentials class CompletionQueue(_types.CompletionQueue): def __init__(self): self.completion_queue = _c.CompletionQueue() def next(self, deadline=float('+inf')): raw_event = self.completion_queue.next(deadline) if raw_event is None: return None event = _types.Event(*raw_event) if event.call is not None: event = event._replace(call=Call(event.call)) if event.call_details is not None: event = event._replace(call_details=_types.CallDetails(*event.call_details)) if event.results is not None: new_results = [_types.OpResult(*r) for r in event.results] new_results = [r if r.status is None else r._replace(status=_types.Status(_types.StatusCode(r.status[0]), r.status[1])) for r in new_results] event = event._replace(results=new_results) return event def shutdown(self): self.completion_queue.shutdown() class Call(_types.Call): def __init__(self, call): self.call = call def start_batch(self, ops, tag): return self.call.start_batch(ops, tag) def cancel(self, code=None, details=None): if code is None and details is None: return self.call.cancel() else: return self.call.cancel(code, details) def peer(self): return self.call.peer() def set_credentials(self, creds): return self.call.set_credentials(creds) class Channel(_types.Channel): def __init__(self, target, args, creds=None): args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)] if creds is None: self.channel = _c.Channel(target, args) else: self.channel = _c.Channel(target, args, creds) def create_call(self, completion_queue, method, host, deadline=None): return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline)) def check_connectivity_state(self, try_to_connect): return self.channel.check_connectivity_state(try_to_connect) def watch_connectivity_state(self, last_observed_state, deadline, completion_queue, tag): self.channel.watch_connectivity_state( last_observed_state, deadline, completion_queue.completion_queue, tag) def target(self): return self.channel.target() _NO_TAG = object() class Server(_types.Server): def __init__(self, completion_queue, args): self.server = _c.Server(completion_queue.completion_queue, args) def add_http2_port(self, addr, creds=None): if creds is None: return self.server.add_http2_port(addr) else: return self.server.add_http2_port(addr, creds) def start(self): return self.server.start() def shutdown(self, tag=None): return self.server.shutdown(tag) def request_call(self, completion_queue, tag): return self.server.request_call(completion_queue.completion_queue, tag) def cancel_all_calls(self): return self.server.cancel_all_calls() grpc-0.11.1/src/python/grpcio/grpc/beta/0000755000175000017500000000000012600663151020160 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio/grpc/beta/_stub.py0000644000175000017500000001061212600663151021646 0ustar apollockapollock# 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. """Beta API stub implementation.""" import threading from grpc._links import invocation from grpc.framework.core import implementations as _core_implementations from grpc.framework.crust import implementations as _crust_implementations from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.links import utilities _DEFAULT_POOL_SIZE = 6 class _AutoIntermediary(object): def __init__(self, delegate, on_deletion): self._delegate = delegate self._on_deletion = on_deletion def __getattr__(self, attr): return getattr(self._delegate, attr) def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): return False def __del__(self): self._on_deletion() def _assemble( channel, host, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size): end_link = _core_implementations.invocation_end_link() grpc_link = invocation.invocation_link( channel, host, metadata_transformer, request_serializers, response_deserializers) if thread_pool is None: invocation_pool = logging_pool.pool( _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size) assembly_pool = invocation_pool else: invocation_pool = thread_pool assembly_pool = None end_link.join_link(grpc_link) grpc_link.join_link(end_link) end_link.start() grpc_link.start() return end_link, grpc_link, invocation_pool, assembly_pool def _disassemble(end_link, grpc_link, pool): end_link.stop(24 * 60 * 60).wait() grpc_link.stop() end_link.join_link(utilities.NULL_LINK) grpc_link.join_link(utilities.NULL_LINK) if pool is not None: pool.shutdown(wait=True) def _wrap_assembly(stub, end_link, grpc_link, assembly_pool): disassembly_thread = threading.Thread( target=_disassemble, args=(end_link, grpc_link, assembly_pool)) return _AutoIntermediary(stub, disassembly_thread.start) def generic_stub( channel, host, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size): end_link, grpc_link, invocation_pool, assembly_pool = _assemble( channel, host, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size) stub = _crust_implementations.generic_stub(end_link, invocation_pool) return _wrap_assembly(stub, end_link, grpc_link, assembly_pool) def dynamic_stub( channel, host, service, cardinalities, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size): end_link, grpc_link, invocation_pool, assembly_pool = _assemble( channel, host, metadata_transformer, request_serializers, response_deserializers, thread_pool, thread_pool_size) stub = _crust_implementations.dynamic_stub( end_link, service, cardinalities, invocation_pool) return _wrap_assembly(stub, end_link, grpc_link, assembly_pool) grpc-0.11.1/src/python/grpcio/grpc/beta/utilities.py0000644000175000017500000001237712600663151022557 0ustar apollockapollock# 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. """Utilities for the gRPC Python Beta API.""" import threading import time # implementations is referenced from specification in this module. from grpc.beta import implementations # pylint: disable=unused-import from grpc.beta import interfaces from grpc.framework.foundation import callable_util from grpc.framework.foundation import future _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = ( 'Exception calling connectivity future "done" callback!') class _ChannelReadyFuture(future.Future): def __init__(self, channel): self._condition = threading.Condition() self._channel = channel self._matured = False self._cancelled = False self._done_callbacks = [] def _block(self, timeout): until = None if timeout is None else time.time() + timeout with self._condition: while True: if self._cancelled: raise future.CancelledError() elif self._matured: return else: if until is None: self._condition.wait() else: remaining = until - time.time() if remaining < 0: raise future.TimeoutError() else: self._condition.wait(timeout=remaining) def _update(self, connectivity): with self._condition: if (not self._cancelled and connectivity is interfaces.ChannelConnectivity.READY): self._matured = True self._channel.unsubscribe(self._update) self._condition.notify_all() done_callbacks = tuple(self._done_callbacks) self._done_callbacks = None else: return for done_callback in done_callbacks: callable_util.call_logging_exceptions( done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self) def cancel(self): with self._condition: if not self._matured: self._cancelled = True self._channel.unsubscribe(self._update) self._condition.notify_all() done_callbacks = tuple(self._done_callbacks) self._done_callbacks = None else: return False for done_callback in done_callbacks: callable_util.call_logging_exceptions( done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self) def cancelled(self): with self._condition: return self._cancelled def running(self): with self._condition: return not self._cancelled and not self._matured def done(self): with self._condition: return self._cancelled or self._matured def result(self, timeout=None): self._block(timeout) return None def exception(self, timeout=None): self._block(timeout) return None def traceback(self, timeout=None): self._block(timeout) return None def add_done_callback(self, fn): with self._condition: if not self._cancelled and not self._matured: self._done_callbacks.append(fn) return fn(self) def start(self): with self._condition: self._channel.subscribe(self._update, try_to_connect=True) def __del__(self): with self._condition: if not self._cancelled and not self._matured: self._channel.unsubscribe(self._update) def channel_ready_future(channel): """Creates a future.Future tracking when an implementations.Channel is ready. Cancelling the returned future.Future does not tell the given implementations.Channel to abandon attempts it may have been making to connect; cancelling merely deactivates the return future.Future's subscription to the given implementations.Channel's connectivity. Args: channel: An implementations.Channel. Returns: A future.Future that matures when the given Channel has connectivity interfaces.ChannelConnectivity.READY. """ ready_future = _ChannelReadyFuture(channel) ready_future.start() return ready_future grpc-0.11.1/src/python/grpcio/grpc/beta/interfaces.py0000644000175000017500000001715412600663151022665 0ustar apollockapollock# 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. """Constants and interfaces of the Beta API of gRPC Python.""" import abc import enum from grpc._adapter import _types @enum.unique class ChannelConnectivity(enum.Enum): """Mirrors grpc_connectivity_state in the gRPC Core. Attributes: IDLE: The channel is idle. CONNECTING: The channel is connecting. READY: The channel is ready to conduct RPCs. TRANSIENT_FAILURE: The channel has seen a failure from which it expects to recover. FATAL_FAILURE: The channel has seen a failure from which it cannot recover. """ IDLE = (_types.ConnectivityState.IDLE, 'idle',) CONNECTING = (_types.ConnectivityState.CONNECTING, 'connecting',) READY = (_types.ConnectivityState.READY, 'ready',) TRANSIENT_FAILURE = ( _types.ConnectivityState.TRANSIENT_FAILURE, 'transient failure',) FATAL_FAILURE = (_types.ConnectivityState.FATAL_FAILURE, 'fatal failure',) @enum.unique class StatusCode(enum.Enum): """Mirrors grpc_status_code in the C core.""" OK = 0 CANCELLED = 1 UNKNOWN = 2 INVALID_ARGUMENT = 3 DEADLINE_EXCEEDED = 4 NOT_FOUND = 5 ALREADY_EXISTS = 6 PERMISSION_DENIED = 7 RESOURCE_EXHAUSTED = 8 FAILED_PRECONDITION = 9 ABORTED = 10 OUT_OF_RANGE = 11 UNIMPLEMENTED = 12 INTERNAL = 13 UNAVAILABLE = 14 DATA_LOSS = 15 UNAUTHENTICATED = 16 class GRPCCallOptions(object): """A value encapsulating gRPC-specific options passed on RPC invocation. This class and its instances have no supported interface - it exists to define the type of its instances and its instances exist to be passed to other functions. """ def __init__(self, disable_compression, subcall_of, credentials): self.disable_compression = disable_compression self.subcall_of = subcall_of self.credentials = credentials def grpc_call_options(disable_compression=False, credentials=None): """Creates a GRPCCallOptions value to be passed at RPC invocation. All parameters are optional and should always be passed by keyword. Args: disable_compression: A boolean indicating whether or not compression should be disabled for the request object of the RPC. Only valid for request-unary RPCs. credentials: A ClientCredentials object to use for the invoked RPC. """ return GRPCCallOptions(disable_compression, None, credentials) class GRPCServicerContext(object): """Exposes gRPC-specific options and behaviors to code servicing RPCs.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def peer(self): """Identifies the peer that invoked the RPC being serviced. Returns: A string identifying the peer that invoked the RPC being serviced. """ raise NotImplementedError() @abc.abstractmethod def disable_next_response_compression(self): """Disables compression of the next response passed by the application.""" raise NotImplementedError() class GRPCInvocationContext(object): """Exposes gRPC-specific options and behaviors to code invoking RPCs.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def disable_next_request_compression(self): """Disables compression of the next request passed by the application.""" raise NotImplementedError() class Server(object): """Services RPCs.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def add_insecure_port(self, address): """Reserves a port for insecure RPC service once this Server becomes active. This method may only be called before calling this Server's start method is called. Args: address: The address for which to open a port. Returns: An integer port on which RPCs will be serviced after this link has been started. This is typically the same number as the port number contained in the passed address, but will likely be different if the port number contained in the passed address was zero. """ raise NotImplementedError() @abc.abstractmethod def add_secure_port(self, address, server_credentials): """Reserves a port for secure RPC service after this Server becomes active. This method may only be called before calling this Server's start method is called. Args: address: The address for which to open a port. server_credentials: A ServerCredentials. Returns: An integer port on which RPCs will be serviced after this link has been started. This is typically the same number as the port number contained in the passed address, but will likely be different if the port number contained in the passed address was zero. """ raise NotImplementedError() @abc.abstractmethod def start(self): """Starts this Server's service of RPCs. This method may only be called while the server is not serving RPCs (i.e. it is not idempotent). """ raise NotImplementedError() @abc.abstractmethod def stop(self, grace): """Stops this Server's service of RPCs. All calls to this method immediately stop service of new RPCs. When existing RPCs are aborted is controlled by the grace period parameter passed to this method. This method may be called at any time and is idempotent. Passing a smaller grace value than has been passed in a previous call will have the effect of stopping the Server sooner. Passing a larger grace value than has been passed in a previous call will not have the effect of stopping the sooner later. Args: grace: A duration of time in seconds to allow existing RPCs to complete before being aborted by this Server's stopping. May be zero for immediate abortion of all in-progress RPCs. Returns: A threading.Event that will be set when this Server has completely stopped. The returned event may not be set until after the full grace period (if some ongoing RPC continues for the full length of the period) of it may be set much sooner (such as if this Server had no RPCs underway at the time it was stopped or if all RPCs that it had underway completed very early in the grace period). """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio/grpc/beta/implementations.py0000644000175000017500000003537012600663151023752 0ustar apollockapollock# 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. """Entry points into the Beta API of gRPC Python.""" # threading is referenced from specification in this module. import abc import enum import threading # pylint: disable=unused-import # cardinality and face are referenced from specification in this module. from grpc._adapter import _intermediary_low from grpc._adapter import _types from grpc.beta import _connectivity_channel from grpc.beta import _server from grpc.beta import _stub from grpc.beta import interfaces from grpc.framework.common import cardinality # pylint: disable=unused-import from grpc.framework.interfaces.face import face # pylint: disable=unused-import _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( 'Exception calling channel subscription callback!') class ClientCredentials(object): """A value encapsulating the data required to create a secure Channel. This class and its instances have no supported interface - it exists to define the type of its instances and its instances exist to be passed to other functions. """ def __init__(self, low_credentials, intermediary_low_credentials): self._low_credentials = low_credentials self._intermediary_low_credentials = intermediary_low_credentials def ssl_client_credentials(root_certificates, private_key, certificate_chain): """Creates a ClientCredentials for use with an SSL-enabled Channel. Args: root_certificates: The PEM-encoded root certificates or None to ask for them to be retrieved from a default location. private_key: The PEM-encoded private key to use or None if no private key should be used. certificate_chain: The PEM-encoded certificate chain to use or None if no certificate chain should be used. Returns: A ClientCredentials for use with an SSL-enabled Channel. """ intermediary_low_credentials = _intermediary_low.ClientCredentials( root_certificates, private_key, certificate_chain) return ClientCredentials( intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access class Channel(object): """A channel to a remote host through which RPCs may be conducted. Only the "subscribe" and "unsubscribe" methods are supported for application use. This class' instance constructor and all other attributes are unsupported. """ def __init__(self, low_channel, intermediary_low_channel): self._low_channel = low_channel self._intermediary_low_channel = intermediary_low_channel self._connectivity_channel = _connectivity_channel.ConnectivityChannel( low_channel) def subscribe(self, callback, try_to_connect=None): """Subscribes to this Channel's connectivity. Args: callback: A callable to be invoked and passed an interfaces.ChannelConnectivity identifying this Channel's connectivity. The callable will be invoked immediately upon subscription and again for every change to this Channel's connectivity thereafter until it is unsubscribed. try_to_connect: A boolean indicating whether or not this Channel should attempt to connect if it is not already connected and ready to conduct RPCs. """ self._connectivity_channel.subscribe(callback, try_to_connect) def unsubscribe(self, callback): """Unsubscribes a callback from this Channel's connectivity. Args: callback: A callable previously registered with this Channel from having been passed to its "subscribe" method. """ self._connectivity_channel.unsubscribe(callback) def insecure_channel(host, port): """Creates an insecure Channel to a remote host. Args: host: The name of the remote host to which to connect. port: The port of the remote host to which to connect. Returns: A Channel to the remote host through which RPCs may be conducted. """ intermediary_low_channel = _intermediary_low.Channel( '%s:%d' % (host, port), None) return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access def secure_channel(host, port, client_credentials): """Creates a secure Channel to a remote host. Args: host: The name of the remote host to which to connect. port: The port of the remote host to which to connect. client_credentials: A ClientCredentials. Returns: A secure Channel to the remote host through which RPCs may be conducted. """ intermediary_low_channel = _intermediary_low.Channel( '%s:%d' % (host, port), client_credentials._intermediary_low_credentials) return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access class StubOptions(object): """A value encapsulating the various options for creation of a Stub. This class and its instances have no supported interface - it exists to define the type of its instances and its instances exist to be passed to other functions. """ def __init__( self, host, request_serializers, response_deserializers, metadata_transformer, thread_pool, thread_pool_size): self.host = host self.request_serializers = request_serializers self.response_deserializers = response_deserializers self.metadata_transformer = metadata_transformer self.thread_pool = thread_pool self.thread_pool_size = thread_pool_size _EMPTY_STUB_OPTIONS = StubOptions( None, None, None, None, None, None) def stub_options( host=None, request_serializers=None, response_deserializers=None, metadata_transformer=None, thread_pool=None, thread_pool_size=None): """Creates a StubOptions value to be passed at stub creation. All parameters are optional and should always be passed by keyword. Args: host: A host string to set on RPC calls. request_serializers: A dictionary from service name-method name pair to request serialization behavior. response_deserializers: A dictionary from service name-method name pair to response deserialization behavior. metadata_transformer: A callable that given a metadata object produces another metadata object to be used in the underlying communication on the wire. thread_pool: A thread pool to use in stubs. thread_pool_size: The size of thread pool to create for use in stubs; ignored if thread_pool has been passed. Returns: A StubOptions value created from the passed parameters. """ return StubOptions( host, request_serializers, response_deserializers, metadata_transformer, thread_pool, thread_pool_size) def generic_stub(channel, options=None): """Creates a face.GenericStub on which RPCs can be made. Args: channel: A Channel for use by the created stub. options: A StubOptions customizing the created stub. Returns: A face.GenericStub on which RPCs can be made. """ effective_options = _EMPTY_STUB_OPTIONS if options is None else options return _stub.generic_stub( channel._intermediary_low_channel, effective_options.host, # pylint: disable=protected-access effective_options.metadata_transformer, effective_options.request_serializers, effective_options.response_deserializers, effective_options.thread_pool, effective_options.thread_pool_size) def dynamic_stub(channel, service, cardinalities, options=None): """Creates a face.DynamicStub with which RPCs can be invoked. Args: channel: A Channel for the returned face.DynamicStub to use. service: The package-qualified full name of the service. cardinalities: A dictionary from RPC method name to cardinality.Cardinality value identifying the cardinality of the RPC method. options: An optional StubOptions value further customizing the functionality of the returned face.DynamicStub. Returns: A face.DynamicStub with which RPCs can be invoked. """ effective_options = StubOptions() if options is None else options return _stub.dynamic_stub( channel._intermediary_low_channel, effective_options.host, service, # pylint: disable=protected-access cardinalities, effective_options.metadata_transformer, effective_options.request_serializers, effective_options.response_deserializers, effective_options.thread_pool, effective_options.thread_pool_size) class ServerCredentials(object): """A value encapsulating the data required to open a secure port on a Server. This class and its instances have no supported interface - it exists to define the type of its instances and its instances exist to be passed to other functions. """ def __init__(self, low_credentials, intermediary_low_credentials): self._low_credentials = low_credentials self._intermediary_low_credentials = intermediary_low_credentials def ssl_server_credentials( private_key_certificate_chain_pairs, root_certificates=None, require_client_auth=False): """Creates a ServerCredentials for use with an SSL-enabled Server. Args: private_key_certificate_chain_pairs: A nonempty sequence each element of which is a pair the first element of which is a PEM-encoded private key and the second element of which is the corresponding PEM-encoded certificate chain. root_certificates: PEM-encoded client root certificates to be used for verifying authenticated clients. If omitted, require_client_auth must also be omitted or be False. require_client_auth: A boolean indicating whether or not to require clients to be authenticated. May only be True if root_certificates is not None. Returns: A ServerCredentials for use with an SSL-enabled Server. """ if len(private_key_certificate_chain_pairs) == 0: raise ValueError( 'At least one private key-certificate chain pairis required!') elif require_client_auth and root_certificates is None: raise ValueError( 'Illegal to require client auth without providing root certificates!') else: intermediary_low_credentials = _intermediary_low.ServerCredentials( root_certificates, private_key_certificate_chain_pairs, require_client_auth) return ServerCredentials( intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access class ServerOptions(object): """A value encapsulating the various options for creation of a Server. This class and its instances have no supported interface - it exists to define the type of its instances and its instances exist to be passed to other functions. """ def __init__( self, multi_method_implementation, request_deserializers, response_serializers, thread_pool, thread_pool_size, default_timeout, maximum_timeout): self.multi_method_implementation = multi_method_implementation self.request_deserializers = request_deserializers self.response_serializers = response_serializers self.thread_pool = thread_pool self.thread_pool_size = thread_pool_size self.default_timeout = default_timeout self.maximum_timeout = maximum_timeout _EMPTY_SERVER_OPTIONS = ServerOptions( None, None, None, None, None, None, None) def server_options( multi_method_implementation=None, request_deserializers=None, response_serializers=None, thread_pool=None, thread_pool_size=None, default_timeout=None, maximum_timeout=None): """Creates a ServerOptions value to be passed at server creation. All parameters are optional and should always be passed by keyword. Args: multi_method_implementation: A face.MultiMethodImplementation to be called to service an RPC if the server has no specific method implementation for the name of the RPC for which service was requested. request_deserializers: A dictionary from service name-method name pair to request deserialization behavior. response_serializers: A dictionary from service name-method name pair to response serialization behavior. thread_pool: A thread pool to use in stubs. thread_pool_size: The size of thread pool to create for use in stubs; ignored if thread_pool has been passed. default_timeout: A duration in seconds to allow for RPC service when servicing RPCs that did not include a timeout value when invoked. maximum_timeout: A duration in seconds to allow for RPC service when servicing RPCs no matter what timeout value was passed when the RPC was invoked. Returns: A StubOptions value created from the passed parameters. """ return ServerOptions( multi_method_implementation, request_deserializers, response_serializers, thread_pool, thread_pool_size, default_timeout, maximum_timeout) def server(service_implementations, options=None): """Creates an interfaces.Server with which RPCs can be serviced. Args: service_implementations: A dictionary from service name-method name pair to face.MethodImplementation. options: An optional ServerOptions value further customizing the functionality of the returned Server. Returns: An interfaces.Server with which RPCs can be serviced. """ effective_options = _EMPTY_SERVER_OPTIONS if options is None else options return _server.server( service_implementations, effective_options.multi_method_implementation, effective_options.request_deserializers, effective_options.response_serializers, effective_options.thread_pool, effective_options.thread_pool_size, effective_options.default_timeout, effective_options.maximum_timeout) grpc-0.11.1/src/python/grpcio/grpc/beta/__init__.py0000644000175000017500000000277012600663151022277 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio/grpc/beta/_server.py0000644000175000017500000001174012600663151022202 0ustar apollockapollock# 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. """Beta API server implementation.""" import threading from grpc._links import service from grpc.beta import interfaces from grpc.framework.core import implementations as _core_implementations from grpc.framework.crust import implementations as _crust_implementations from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.base import base from grpc.framework.interfaces.links import utilities _DEFAULT_POOL_SIZE = 8 _DEFAULT_TIMEOUT = 300 _MAXIMUM_TIMEOUT = 24 * 60 * 60 class _GRPCServicer(base.Servicer): def __init__(self, delegate): self._delegate = delegate def service(self, group, method, context, output_operator): try: return self._delegate.service(group, method, context, output_operator) except base.NoSuchMethodError as e: if e.code is None and e.details is None: raise base.NoSuchMethodError( interfaces.StatusCode.UNIMPLEMENTED, b'Method "%s" of service "%s" not implemented!' % (method, group)) else: raise def _disassemble(grpc_link, end_link, pool, event, grace): grpc_link.begin_stop() end_link.stop(grace).wait() grpc_link.end_stop() grpc_link.join_link(utilities.NULL_LINK) end_link.join_link(utilities.NULL_LINK) if pool is not None: pool.shutdown(wait=True) event.set() class Server(interfaces.Server): def __init__(self, grpc_link, end_link, pool): self._grpc_link = grpc_link self._end_link = end_link self._pool = pool def add_insecure_port(self, address): return self._grpc_link.add_port(address, None) def add_secure_port(self, address, server_credentials): return self._grpc_link.add_port( address, server_credentials._intermediary_low_credentials) # pylint: disable=protected-access def _start(self): self._grpc_link.join_link(self._end_link) self._end_link.join_link(self._grpc_link) self._grpc_link.start() self._end_link.start() def _stop(self, grace): stop_event = threading.Event() if 0 < grace: disassembly_thread = threading.Thread( target=_disassemble, args=( self._grpc_link, self._end_link, self._pool, stop_event, grace,)) disassembly_thread.start() return stop_event else: _disassemble(self._grpc_link, self._end_link, self._pool, stop_event, 0) return stop_event def start(self): self._start() def stop(self, grace): return self._stop(grace) def __enter__(self): self._start() return self def __exit__(self, exc_type, exc_val, exc_tb): self._stop(0).wait() return False def server( implementations, multi_implementation, request_deserializers, response_serializers, thread_pool, thread_pool_size, default_timeout, maximum_timeout): if thread_pool is None: service_thread_pool = logging_pool.pool( _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size) assembly_thread_pool = service_thread_pool else: service_thread_pool = thread_pool assembly_thread_pool = None servicer = _GRPCServicer( _crust_implementations.servicer( implementations, multi_implementation, service_thread_pool)) grpc_link = service.service_link(request_deserializers, response_serializers) end_link = _core_implementations.service_end_link( servicer, _DEFAULT_TIMEOUT if default_timeout is None else default_timeout, _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout) return Server(grpc_link, end_link, assembly_thread_pool) grpc-0.11.1/src/python/grpcio/grpc/beta/_connectivity_channel.py0000644000175000017500000001435312600663151025105 0ustar apollockapollock# 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. """Affords a connectivity-state-listenable channel.""" import threading import time from grpc._adapter import _low from grpc._adapter import _types from grpc.beta import interfaces from grpc.framework.foundation import callable_util _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( 'Exception calling channel subscription callback!') _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = { state: connectivity for state, connectivity in zip( _types.ConnectivityState, interfaces.ChannelConnectivity) } class ConnectivityChannel(object): def __init__(self, low_channel): self._lock = threading.Lock() self._low_channel = low_channel self._polling = False self._connectivity = None self._try_to_connect = False self._callbacks_and_connectivities = [] self._delivering = False def _deliveries(self, connectivity): callbacks_needing_update = [] for callback_and_connectivity in self._callbacks_and_connectivities: callback, callback_connectivity = callback_and_connectivity if callback_connectivity is not connectivity: callbacks_needing_update.append(callback) callback_and_connectivity[1] = connectivity return callbacks_needing_update def _deliver(self, initial_connectivity, initial_callbacks): connectivity = initial_connectivity callbacks = initial_callbacks while True: for callback in callbacks: callable_util.call_logging_exceptions( callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE, connectivity) with self._lock: callbacks = self._deliveries(self._connectivity) if callbacks: connectivity = self._connectivity else: self._delivering = False return def _spawn_delivery(self, connectivity, callbacks): delivering_thread = threading.Thread( target=self._deliver, args=(connectivity, callbacks,)) delivering_thread.start() self._delivering = True # TODO(issue 3064): Don't poll. def _poll_connectivity(self, low_channel, initial_try_to_connect): try_to_connect = initial_try_to_connect low_connectivity = low_channel.check_connectivity_state(try_to_connect) with self._lock: self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[ low_connectivity] callbacks = tuple( callback for callback, unused_but_known_to_be_none_connectivity in self._callbacks_and_connectivities) for callback_and_connectivity in self._callbacks_and_connectivities: callback_and_connectivity[1] = self._connectivity if callbacks: self._spawn_delivery(self._connectivity, callbacks) completion_queue = _low.CompletionQueue() while True: low_channel.watch_connectivity_state( low_connectivity, time.time() + 0.2, completion_queue, None) event = completion_queue.next() with self._lock: if not self._callbacks_and_connectivities and not self._try_to_connect: self._polling = False self._connectivity = None completion_queue.shutdown() break try_to_connect = self._try_to_connect self._try_to_connect = False if event.success or try_to_connect: low_connectivity = low_channel.check_connectivity_state(try_to_connect) with self._lock: self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[ low_connectivity] if not self._delivering: callbacks = self._deliveries(self._connectivity) if callbacks: self._spawn_delivery(self._connectivity, callbacks) def subscribe(self, callback, try_to_connect): with self._lock: if not self._callbacks_and_connectivities and not self._polling: polling_thread = threading.Thread( target=self._poll_connectivity, args=(self._low_channel, bool(try_to_connect))) polling_thread.start() self._polling = True self._callbacks_and_connectivities.append([callback, None]) elif not self._delivering and self._connectivity is not None: self._spawn_delivery(self._connectivity, (callback,)) self._try_to_connect |= bool(try_to_connect) self._callbacks_and_connectivities.append( [callback, self._connectivity]) else: self._try_to_connect |= bool(try_to_connect) self._callbacks_and_connectivities.append([callback, None]) def unsubscribe(self, callback): with self._lock: for index, (subscribed_callback, unused_connectivity) in enumerate( self._callbacks_and_connectivities): if callback == subscribed_callback: self._callbacks_and_connectivities.pop(index) break def low_channel(self): return self._low_channel grpc-0.11.1/src/python/grpcio/setup.cfg0000644000175000017500000000002612600663151020131 0ustar apollockapollock[build_ext] inplace=1 grpc-0.11.1/src/python/grpcio/MANIFEST.in0000644000175000017500000000007012600663151020045 0ustar apollockapollockgraft grpc include commands.py include requirements.txt grpc-0.11.1/src/python/grpcio/README.rst0000644000175000017500000000140012600663151017774 0ustar apollockapollockgRPC Python =========== Package for GRPC Python. Dependencies ------------ Ensure you have installed the gRPC core. On Mac OS X, install homebrew_. Run the following command to install gRPC Python. :: $ curl -fsSL https://goo.gl/getgrpc | bash -s python This will download and run the [gRPC install script][] to install grpc core. The script then uses pip to install this package. It also installs the Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin for python. Otherwise, `install from source`_ .. _`install from source`: https://github.com/grpc/grpc/blob/master/src/python/README.md#building-from-source .. _homebrew: http://brew.sh .. _`gRPC install script`: https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install grpc-0.11.1/src/python/grpcio/commands.py0000644000175000017500000000657212600663151020477 0ustar apollockapollock# 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. """Provides distutils command classes for the GRPC Python setup process.""" import os import os.path import sys import setuptools from setuptools.command import build_py _CONF_PY_ADDENDUM = """ extensions.append('sphinx.ext.napoleon') napoleon_google_docstring = True napoleon_numpy_docstring = True html_theme = 'sphinx_rtd_theme' """ class SphinxDocumentation(setuptools.Command): """Command to generate documentation via sphinx.""" description = '' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): # We import here to ensure that setup.py has had a chance to install the # relevant package eggs first. import sphinx import sphinx.apidoc metadata = self.distribution.metadata src_dir = os.path.join( os.getcwd(), self.distribution.package_dir[''], 'grpc') sys.path.append(src_dir) sphinx.apidoc.main([ '', '--force', '--full', '-H', metadata.name, '-A', metadata.author, '-V', metadata.version, '-R', metadata.version, '-o', os.path.join('doc', 'src'), src_dir]) conf_filepath = os.path.join('doc', 'src', 'conf.py') with open(conf_filepath, 'a') as conf_file: conf_file.write(_CONF_PY_ADDENDUM) sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')]) class BuildProjectMetadata(setuptools.Command): """Command to generate project metadata in a module.""" description = '' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): with open('grpc/_grpcio_metadata.py', 'w') as module_file: module_file.write('__version__ = """{}"""'.format( self.distribution.get_version())) class BuildPy(build_py.build_py): """Custom project build command.""" def run(self): self.run_command('build_project_metadata') build_py.build_py.run(self) grpc-0.11.1/src/python/grpcio/setup.py0000644000175000017500000000716012600663151020030 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A setup module for the GRPC Python package.""" import os import os.path import sys from distutils import core as _core import setuptools # Ensure we're in the proper directory whether or not we're being used by pip. os.chdir(os.path.dirname(os.path.abspath(__file__))) # Break import-style to ensure we can actually find our commands module. import commands # Use environment variables to determine whether or not the Cython extension # should *use* Cython or use the generated C files. Note that this requires the # C files to have been generated by building first *with* Cython support. _BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False) _C_EXTENSION_SOURCES = ( 'grpc/_adapter/_c/module.c', 'grpc/_adapter/_c/types.c', 'grpc/_adapter/_c/utility.c', 'grpc/_adapter/_c/types/client_credentials.c', 'grpc/_adapter/_c/types/server_credentials.c', 'grpc/_adapter/_c/types/completion_queue.c', 'grpc/_adapter/_c/types/call.c', 'grpc/_adapter/_c/types/channel.c', 'grpc/_adapter/_c/types/server.c', ) _EXTENSION_INCLUDE_DIRECTORIES = ( '.', ) _EXTENSION_LIBRARIES = ( 'grpc', 'gpr', ) if not "darwin" in sys.platform: _EXTENSION_LIBRARIES += ('rt',) _C_EXTENSION_MODULE = _core.Extension( 'grpc._adapter._c', sources=list(_C_EXTENSION_SOURCES), include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES), libraries=list(_EXTENSION_LIBRARIES), ) _EXTENSION_MODULES = [_C_EXTENSION_MODULE] _PACKAGES = ( setuptools.find_packages('.', exclude=['*._cython', '*._cython.*']) ) _PACKAGE_DIRECTORIES = { '': '.', } _INSTALL_REQUIRES = ( 'enum34>=1.0.4', 'futures>=2.2.0', ) _SETUP_REQUIRES = ( 'sphinx>=1.3', ) + _INSTALL_REQUIRES _COMMAND_CLASS = { 'doc': commands.SphinxDocumentation, 'build_project_metadata': commands.BuildProjectMetadata, 'build_py': commands.BuildPy, } setuptools.setup( name='grpcio', version='0.11.0b1', ext_modules=_EXTENSION_MODULES, packages=list(_PACKAGES), package_dir=_PACKAGE_DIRECTORIES, install_requires=_INSTALL_REQUIRES, setup_requires=_SETUP_REQUIRES, cmdclass=_COMMAND_CLASS ) grpc-0.11.1/src/python/grpcio/requirements.txt0000644000175000017500000000003512600663151021574 0ustar apollockapollockenum34>=1.0.4 futures>=2.2.0 grpc-0.11.1/src/python/grpcio/.gitignore0000644000175000017500000000012012600663151020273 0ustar apollockapollockMANIFEST *.egg-info/ build/ dist/ *.egg *.egg/ *.eggs/ doc/ _grpcio_metadata.py grpc-0.11.1/src/python/grpcio_health_checking/0000755000175000017500000000000012600663151021472 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_health_checking/grpc/0000755000175000017500000000000012600663151022425 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_health_checking/grpc/__init__.py0000644000175000017500000000277212600663151024546 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_health_checking/grpc/health/0000755000175000017500000000000012600663151023672 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_health_checking/grpc/health/v1alpha/0000755000175000017500000000000012600663151025226 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_health_checking/grpc/health/v1alpha/health.proto0000644000175000017500000000353612600663151027567 0ustar apollockapollock// 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. syntax = "proto3"; package grpc.health.v1alpha; message HealthCheckRequest { string service = 1; } message HealthCheckResponse { enum ServingStatus { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; } ServingStatus status = 1; } service Health { rpc Check(HealthCheckRequest) returns (HealthCheckResponse); } grpc-0.11.1/src/python/grpcio_health_checking/grpc/health/v1alpha/__init__.py0000644000175000017500000000277212600663151027347 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_health_checking/grpc/health/v1alpha/health.py0000644000175000017500000001110112600663151027037 0ustar apollockapollock# 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. """Reference implementation for health checking in gRPC Python.""" import abc import enum import threading from grpc.health.v1alpha import health_pb2 @enum.unique class HealthStatus(enum.Enum): """Statuses for a service mirroring the reference health.proto's values.""" UNKNOWN = health_pb2.HealthCheckResponse.UNKNOWN SERVING = health_pb2.HealthCheckResponse.SERVING NOT_SERVING = health_pb2.HealthCheckResponse.NOT_SERVING class _HealthServicer(health_pb2.EarlyAdopterHealthServicer): """Servicer handling RPCs for service statuses.""" def __init__(self): self._server_status_lock = threading.Lock() self._server_status = {} def Check(self, request, context): with self._server_status_lock: if request.service not in self._server_status: # TODO(atash): once the Python API has a way of setting the server # status, bring us into conformance with the health check spec by # returning the NOT_FOUND status here. raise NotImplementedError() else: return health_pb2.HealthCheckResponse( status=self._server_status[request.service].value) def set(service, status): if not isinstance(status, HealthStatus): raise TypeError('expected grpc.health.v1alpha.health.HealthStatus ' 'for argument `status` but got {}'.format(status)) with self._server_status_lock: self._server_status[service] = status class HealthServer(health_pb2.EarlyAdopterHealthServer): """Interface for the reference gRPC Python health server.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def start(self): raise NotImplementedError() @abc.abstractmethod def stop(self): raise NotImplementedError() @abc.abstractmethod def set(self, service, status): """Set the status of the given service. Args: service (str): service name of the service to set the reported status of status (HealthStatus): status to set for the specified service """ raise NotImplementedError() class _HealthServerImplementation(HealthServer): """Implementation for the reference gRPC Python health server.""" def __init__(self, server, servicer): self._server = server self._servicer = servicer def start(self): self._server.start() def stop(self): self._server.stop() def set(self, service, status): self._servicer.set(service, status) def create_Health_server(port, private_key=None, certificate_chain=None): """Get a HealthServer instance. Args: port (int): port number passed through to health_pb2 server creation routine. private_key (str): to-be-created server's desired private key certificate_chain (str): to-be-created server's desired certificate chain Returns: An instance of HealthServer (conforming thus to EarlyAdopterHealthServer and providing a method to set server status).""" servicer = _HealthServicer() server = health_pb2.early_adopter_create_Health_server( servicer, port=port, private_key=private_key, certificate_chain=certificate_chain) return _HealthServerImplementation(server, servicer) grpc-0.11.1/src/python/grpcio_health_checking/grpc/health/__init__.py0000644000175000017500000000277212600663151026013 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_health_checking/MANIFEST.in0000644000175000017500000000003712600663151023230 0ustar apollockapollockgraft grpc include commands.py grpc-0.11.1/src/python/grpcio_health_checking/README.rst0000644000175000017500000000032712600663151023163 0ustar apollockapollockgRPC Python Health Checking =========================== Reference package for GRPC Python health checking. Dependencies ------------ Depends on the `grpcio` package, available from PyPI via `pip install grpcio`. grpc-0.11.1/src/python/grpcio_health_checking/commands.py0000644000175000017500000000556212600663151023655 0ustar apollockapollock# 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. """Provides distutils command classes for the GRPC Python setup process.""" import distutils import glob import os import os.path import subprocess import sys import setuptools from setuptools.command import build_py class BuildProtoModules(setuptools.Command): """Command to generate project *_pb2.py modules from proto files.""" description = '' user_options = [] def initialize_options(self): pass def finalize_options(self): self.protoc_command = 'protoc' self.grpc_python_plugin_command = distutils.spawn.find_executable( 'grpc_python_plugin') def run(self): paths = [] root_directory = os.getcwd() for walk_root, directories, filenames in os.walk(root_directory): for filename in filenames: if filename.endswith('.proto'): paths.append(os.path.join(walk_root, filename)) command = [ self.protoc_command, '--plugin=protoc-gen-python-grpc={}'.format( self.grpc_python_plugin_command), '-I {}'.format(root_directory), '--python_out={}'.format(root_directory), '--python-grpc_out={}'.format(root_directory), ] + paths subprocess.check_call(' '.join(command), cwd=root_directory, shell=True) class BuildPy(build_py.build_py): """Custom project build command.""" def run(self): self.run_command('build_proto_modules') build_py.build_py.run(self) grpc-0.11.1/src/python/grpcio_health_checking/setup.py0000644000175000017500000000463412600663151023213 0ustar apollockapollock# 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. """Setup module for the GRPC Python package's optional health checking.""" import os import os.path import sys from distutils import core as _core import setuptools # Ensure we're in the proper directory whether or not we're being used by pip. os.chdir(os.path.dirname(os.path.abspath(__file__))) # Break import-style to ensure we can actually find our commands module. import commands _PACKAGES = ( setuptools.find_packages('.') ) _PACKAGE_DIRECTORIES = { '': '.', } _INSTALL_REQUIRES = ( 'grpcio>=0.11.0b0', ) _SETUP_REQUIRES = _INSTALL_REQUIRES _COMMAND_CLASS = { 'build_proto_modules': commands.BuildProtoModules, 'build_py': commands.BuildPy, } setuptools.setup( name='grpcio_health_checking', version='0.11.0b0', packages=list(_PACKAGES), package_dir=_PACKAGE_DIRECTORIES, install_requires=_INSTALL_REQUIRES, setup_requires=_SETUP_REQUIRES, cmdclass=_COMMAND_CLASS ) grpc-0.11.1/src/python/grpcio_test/0000755000175000017500000000000012600663151017351 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/setup.cfg0000644000175000017500000000007212600663151021171 0ustar apollockapollock[pytest] norecursedirs = _cython python_files = *_test.py grpc-0.11.1/src/python/grpcio_test/grpc_protoc_plugin/0000755000175000017500000000000012600663151023250 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_protoc_plugin/python_plugin_test.py0000644000175000017500000005276712600663151027601 0ustar apollockapollock# 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. import argparse import contextlib import distutils.spawn import errno import itertools import os import pkg_resources import shutil import subprocess import sys import tempfile import threading import time import unittest from grpc.framework.alpha import exceptions from grpc.framework.foundation import future # Identifiers of entities we expect to find in the generated module. SERVICER_IDENTIFIER = 'EarlyAdopterTestServiceServicer' SERVER_IDENTIFIER = 'EarlyAdopterTestServiceServer' STUB_IDENTIFIER = 'EarlyAdopterTestServiceStub' SERVER_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_server' STUB_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_stub' # The timeout used in tests of RPCs that are supposed to expire. SHORT_TIMEOUT = 2 # The timeout used in tests of RPCs that are not supposed to expire. The # absurdly large value doesn't matter since no passing execution of this test # module will ever wait the duration. LONG_TIMEOUT = 600 NO_DELAY = 0 class _ServicerMethods(object): def __init__(self, test_pb2, delay): self._condition = threading.Condition() self._delay = delay self._paused = False self._fail = False self._test_pb2 = test_pb2 @contextlib.contextmanager def pause(self): # pylint: disable=invalid-name with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() @contextlib.contextmanager def fail(self): # pylint: disable=invalid-name with self._condition: self._fail = True yield with self._condition: self._fail = False def _control(self): # pylint: disable=invalid-name with self._condition: if self._fail: raise ValueError() while self._paused: self._condition.wait() time.sleep(self._delay) def UnaryCall(self, request, unused_rpc_context): response = self._test_pb2.SimpleResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * request.response_size self._control() return response def StreamingOutputCall(self, request, unused_rpc_context): for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() yield response def StreamingInputCall(self, request_iter, unused_rpc_context): response = self._test_pb2.StreamingInputCallResponse() aggregated_payload_size = 0 for request in request_iter: aggregated_payload_size += len(request.payload.payload_compressable) response.aggregated_payload_size = aggregated_payload_size self._control() return response def FullDuplexCall(self, request_iter, unused_rpc_context): for request in request_iter: for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() yield response def HalfDuplexCall(self, request_iter, unused_rpc_context): responses = [] for request in request_iter: for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() responses.append(response) for response in responses: yield response @contextlib.contextmanager def _CreateService(test_pb2, delay): """Provides a servicer backend and a stub. The servicer is just the implementation of the actual servicer passed to the face player of the python RPC implementation; the two are detached. Non-zero delay puts a delay on each call to the servicer, representative of communication latency. Timeout is the default timeout for the stub while waiting for the service. Args: test_pb2: The test_pb2 module generated by this test. delay: Delay in seconds per response from the servicer. Yields: A (servicer_methods, servicer, stub) three-tuple where servicer_methods is the back-end of the service bound to the stub and the server and stub are both activated and ready for use. """ servicer_methods = _ServicerMethods(test_pb2, delay) class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)): def UnaryCall(self, request, context): return servicer_methods.UnaryCall(request, context) def StreamingOutputCall(self, request, context): return servicer_methods.StreamingOutputCall(request, context) def StreamingInputCall(self, request_iter, context): return servicer_methods.StreamingInputCall(request_iter, context) def FullDuplexCall(self, request_iter, context): return servicer_methods.FullDuplexCall(request_iter, context) def HalfDuplexCall(self, request_iter, context): return servicer_methods.HalfDuplexCall(request_iter, context) servicer = Servicer() server = getattr( test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer, 0) with server: port = server.port() stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)('localhost', port) with stub: yield servicer_methods, stub, server def _streaming_input_request_iterator(test_pb2): for _ in range(3): request = test_pb2.StreamingInputCallRequest() request.payload.payload_type = test_pb2.COMPRESSABLE request.payload.payload_compressable = 'a' yield request def _streaming_output_request(test_pb2): request = test_pb2.StreamingOutputCallRequest() sizes = [1, 2, 3] request.response_parameters.add(size=sizes[0], interval_us=0) request.response_parameters.add(size=sizes[1], interval_us=0) request.response_parameters.add(size=sizes[2], interval_us=0) return request def _full_duplex_request_iterator(test_pb2): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=2, interval_us=0) request.response_parameters.add(size=3, interval_us=0) yield request class PythonPluginTest(unittest.TestCase): """Test case for the gRPC Python protoc-plugin. While reading these tests, remember that the futures API (`stub.method.async()`) only gives futures for the *non-streaming* responses, else it behaves like its blocking cousin. """ def setUp(self): # Assume that the appropriate protoc and grpc_python_plugins are on the # path. protoc_command = 'protoc' protoc_plugin_filename = distutils.spawn.find_executable( 'grpc_python_plugin') test_proto_filename = pkg_resources.resource_filename( 'grpc_protoc_plugin', 'test.proto') if not os.path.isfile(protoc_command): # Assume that if we haven't built protoc that it's on the system. protoc_command = 'protoc' # Ensure that the output directory exists. self.outdir = tempfile.mkdtemp() # Invoke protoc with the plugin. cmd = [ protoc_command, '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename, '-I .', '--python_out=%s' % self.outdir, '--python-grpc_out=%s' % self.outdir, os.path.basename(test_proto_filename), ] subprocess.check_call(' '.join(cmd), shell=True, env=os.environ, cwd=os.path.dirname(test_proto_filename)) sys.path.append(self.outdir) def tearDown(self): try: shutil.rmtree(self.outdir) except OSError as exc: if exc.errno != errno.ENOENT: raise # TODO(atash): Figure out which of these tests is hanging flakily with small # probability. def testImportAttributes(self): # check that we can access the generated module and its members. import test_pb2 # pylint: disable=g-import-not-at-top self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, SERVER_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_FACTORY_IDENTIFIER, None)) def testUpDown(self): import test_pb2 with _CreateService( test_pb2, NO_DELAY) as (servicer, stub, unused_server): request = test_pb2.SimpleRequest(response_size=13) def testUnaryCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods. request = test_pb2.SimpleRequest(response_size=13) response = stub.UnaryCall(request, timeout) expected_response = methods.UnaryCall(request, 'not a real RpcContext!') self.assertEqual(expected_response, response) def testUnaryCallAsync(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): # Check that the call does not block waiting for the server to respond. with methods.pause(): response_future = stub.UnaryCall.async(request, LONG_TIMEOUT) response = response_future.result() expected_response = methods.UnaryCall(request, 'not a real RpcContext!') self.assertEqual(expected_response, response) def testUnaryCallAsyncExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): request = test_pb2.SimpleRequest(response_size=13) with methods.pause(): response_future = stub.UnaryCall.async(request, SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): response_future.result() @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testUnaryCallAsyncCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): response_future = stub.UnaryCall.async(request, 1) response_future.cancel() self.assertTrue(response_future.cancelled()) def testUnaryCallAsyncFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): response_future = stub.UnaryCall.async(request, LONG_TIMEOUT) self.assertIsNotNone(response_future.exception()) def testStreamingOutputCall(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): responses = stub.StreamingOutputCall(request, LONG_TIMEOUT) expected_responses = methods.StreamingOutputCall( request, 'not a real RpcContext!') for expected_response, response in itertools.izip_longest( expected_responses, responses): self.assertEqual(expected_response, response) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testStreamingOutputCallExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testStreamingOutputCallCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( unused_methods, stub, unused_server): responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT) next(responses) responses.cancel() with self.assertRaises(future.CancelledError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this times out ' 'instead of raising the proper error.') def testStreamingOutputCallFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): responses = stub.StreamingOutputCall(request, 1) self.assertIsNotNone(responses) with self.assertRaises(exceptions.ServicerError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testStreamingInputCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): response = stub.StreamingInputCall( _streaming_input_request_iterator(test_pb2), LONG_TIMEOUT) expected_response = methods.StreamingInputCall( _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!') self.assertEqual(expected_response, response) def testStreamingInputCallAsync(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), LONG_TIMEOUT) response = response_future.result() expected_response = methods.StreamingInputCall( _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!') self.assertEqual(expected_response, response) def testStreamingInputCallAsyncExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): response_future.result() self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) def testStreamingInputCallAsyncCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods. response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), timeout) response_future.cancel() self.assertTrue(response_future.cancelled()) with self.assertRaises(future.CancelledError): response_future.result() def testStreamingInputCallAsyncFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), SHORT_TIMEOUT) self.assertIsNotNone(response_future.exception()) def testFullDuplexCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): responses = stub.FullDuplexCall( _full_duplex_request_iterator(test_pb2), LONG_TIMEOUT) expected_responses = methods.FullDuplexCall( _full_duplex_request_iterator(test_pb2), 'not a real RpcContext!') for expected_response, response in itertools.izip_longest( expected_responses, responses): self.assertEqual(expected_response, response) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testFullDuplexCallExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): responses = stub.FullDuplexCall(request_iterator, SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testFullDuplexCallCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): request_iterator = _full_duplex_request_iterator(test_pb2) responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT) next(responses) responses.cancel() with self.assertRaises(future.CancelledError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this hangs forever ' 'and fix.') def testFullDuplexCallFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT) self.assertIsNotNone(responses) with self.assertRaises(exceptions.ServicerError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testHalfDuplexCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=2, interval_us=0) request.response_parameters.add(size=3, interval_us=0) yield request responses = stub.HalfDuplexCall( half_duplex_request_iterator(), LONG_TIMEOUT) expected_responses = methods.HalfDuplexCall( half_duplex_request_iterator(), 'not a real RpcContext!') for check in itertools.izip_longest(expected_responses, responses): expected_response, response = check self.assertEqual(expected_response, response) def testHalfDuplexCallWedged(self): import test_pb2 # pylint: disable=g-import-not-at-top condition = threading.Condition() wait_cell = [False] @contextlib.contextmanager def wait(): # pylint: disable=invalid-name # Where's Python 3's 'nonlocal' statement when you need it? with condition: wait_cell[0] = True yield with condition: wait_cell[0] = False condition.notify_all() def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request with condition: while wait_cell[0]: condition.wait() with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): with wait(): responses = stub.HalfDuplexCall( half_duplex_request_iterator(), SHORT_TIMEOUT) # half-duplex waits for the client to send all info with self.assertRaises(exceptions.ExpirationError): next(responses) if __name__ == '__main__': os.chdir(os.path.dirname(sys.argv[0])) unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py0000644000175000017500000004656012600663151030566 0ustar apollockapollock# 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. import argparse import contextlib import distutils.spawn import errno import itertools import os import pkg_resources import shutil import subprocess import sys import tempfile import threading import time import unittest from grpc.beta import implementations from grpc.framework.foundation import future from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants # Identifiers of entities we expect to find in the generated module. SERVICER_IDENTIFIER = 'BetaTestServiceServicer' STUB_IDENTIFIER = 'BetaTestServiceStub' SERVER_FACTORY_IDENTIFIER = 'beta_create_TestService_server' STUB_FACTORY_IDENTIFIER = 'beta_create_TestService_stub' class _ServicerMethods(object): def __init__(self, test_pb2): self._condition = threading.Condition() self._paused = False self._fail = False self._test_pb2 = test_pb2 @contextlib.contextmanager def pause(self): # pylint: disable=invalid-name with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() @contextlib.contextmanager def fail(self): # pylint: disable=invalid-name with self._condition: self._fail = True yield with self._condition: self._fail = False def _control(self): # pylint: disable=invalid-name with self._condition: if self._fail: raise ValueError() while self._paused: self._condition.wait() def UnaryCall(self, request, unused_rpc_context): response = self._test_pb2.SimpleResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * request.response_size self._control() return response def StreamingOutputCall(self, request, unused_rpc_context): for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() yield response def StreamingInputCall(self, request_iter, unused_rpc_context): response = self._test_pb2.StreamingInputCallResponse() aggregated_payload_size = 0 for request in request_iter: aggregated_payload_size += len(request.payload.payload_compressable) response.aggregated_payload_size = aggregated_payload_size self._control() return response def FullDuplexCall(self, request_iter, unused_rpc_context): for request in request_iter: for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() yield response def HalfDuplexCall(self, request_iter, unused_rpc_context): responses = [] for request in request_iter: for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() responses.append(response) for response in responses: yield response @contextlib.contextmanager def _CreateService(test_pb2): """Provides a servicer backend and a stub. The servicer is just the implementation of the actual servicer passed to the face player of the python RPC implementation; the two are detached. Args: test_pb2: The test_pb2 module generated by this test. Yields: A (servicer_methods, stub) pair where servicer_methods is the back-end of the service bound to the stub and and stub is the stub on which to invoke RPCs. """ servicer_methods = _ServicerMethods(test_pb2) class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)): def UnaryCall(self, request, context): return servicer_methods.UnaryCall(request, context) def StreamingOutputCall(self, request, context): return servicer_methods.StreamingOutputCall(request, context) def StreamingInputCall(self, request_iter, context): return servicer_methods.StreamingInputCall(request_iter, context) def FullDuplexCall(self, request_iter, context): return servicer_methods.FullDuplexCall(request_iter, context) def HalfDuplexCall(self, request_iter, context): return servicer_methods.HalfDuplexCall(request_iter, context) servicer = Servicer() server = getattr(test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer) port = server.add_insecure_port('[::]:0') server.start() channel = implementations.insecure_channel('localhost', port) stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)(channel) yield servicer_methods, stub server.stop(0) def _streaming_input_request_iterator(test_pb2): for _ in range(3): request = test_pb2.StreamingInputCallRequest() request.payload.payload_type = test_pb2.COMPRESSABLE request.payload.payload_compressable = 'a' yield request def _streaming_output_request(test_pb2): request = test_pb2.StreamingOutputCallRequest() sizes = [1, 2, 3] request.response_parameters.add(size=sizes[0], interval_us=0) request.response_parameters.add(size=sizes[1], interval_us=0) request.response_parameters.add(size=sizes[2], interval_us=0) return request def _full_duplex_request_iterator(test_pb2): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=2, interval_us=0) request.response_parameters.add(size=3, interval_us=0) yield request class PythonPluginTest(unittest.TestCase): """Test case for the gRPC Python protoc-plugin. While reading these tests, remember that the futures API (`stub.method.future()`) only gives futures for the *response-unary* methods and does not exist for response-streaming methods. """ def setUp(self): # Assume that the appropriate protoc and grpc_python_plugins are on the # path. protoc_command = 'protoc' protoc_plugin_filename = distutils.spawn.find_executable( 'grpc_python_plugin') test_proto_filename = pkg_resources.resource_filename( 'grpc_protoc_plugin', 'test.proto') if not os.path.isfile(protoc_command): # Assume that if we haven't built protoc that it's on the system. protoc_command = 'protoc' # Ensure that the output directory exists. self.outdir = tempfile.mkdtemp() # Invoke protoc with the plugin. cmd = [ protoc_command, '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename, '-I .', '--python_out=%s' % self.outdir, '--python-grpc_out=%s' % self.outdir, os.path.basename(test_proto_filename), ] subprocess.check_call(' '.join(cmd), shell=True, env=os.environ, cwd=os.path.dirname(test_proto_filename)) sys.path.append(self.outdir) def tearDown(self): try: shutil.rmtree(self.outdir) except OSError as exc: if exc.errno != errno.ENOENT: raise def testImportAttributes(self): # check that we can access the generated module and its members. import test_pb2 # pylint: disable=g-import-not-at-top self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_FACTORY_IDENTIFIER, None)) def testUpDown(self): import test_pb2 with _CreateService(test_pb2) as (servicer, stub): request = test_pb2.SimpleRequest(response_size=13) def testUnaryCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): request = test_pb2.SimpleRequest(response_size=13) response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT) expected_response = methods.UnaryCall(request, 'not a real context!') self.assertEqual(expected_response, response) def testUnaryCallFuture(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2) as (methods, stub): # Check that the call does not block waiting for the server to respond. with methods.pause(): response_future = stub.UnaryCall.future( request, test_constants.LONG_TIMEOUT) response = response_future.result() expected_response = methods.UnaryCall(request, 'not a real RpcContext!') self.assertEqual(expected_response, response) def testUnaryCallFutureExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): request = test_pb2.SimpleRequest(response_size=13) with methods.pause(): response_future = stub.UnaryCall.future( request, test_constants.SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): response_future.result() def testUnaryCallFutureCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.UnaryCall.future(request, 1) response_future.cancel() self.assertTrue(response_future.cancelled()) def testUnaryCallFutureFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): response_future = stub.UnaryCall.future( request, test_constants.LONG_TIMEOUT) self.assertIsNotNone(response_future.exception()) def testStreamingOutputCall(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (methods, stub): responses = stub.StreamingOutputCall( request, test_constants.LONG_TIMEOUT) expected_responses = methods.StreamingOutputCall( request, 'not a real RpcContext!') for expected_response, response in itertools.izip_longest( expected_responses, responses): self.assertEqual(expected_response, response) def testStreamingOutputCallExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): responses = stub.StreamingOutputCall( request, test_constants.SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(responses) def testStreamingOutputCallCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (unused_methods, stub): responses = stub.StreamingOutputCall( request, test_constants.LONG_TIMEOUT) next(responses) responses.cancel() with self.assertRaises(face.CancellationError): next(responses) def testStreamingOutputCallFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): responses = stub.StreamingOutputCall(request, 1) self.assertIsNotNone(responses) with self.assertRaises(face.RemoteError): next(responses) def testStreamingInputCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): response = stub.StreamingInputCall( _streaming_input_request_iterator(test_pb2), test_constants.LONG_TIMEOUT) expected_response = methods.StreamingInputCall( _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!') self.assertEqual(expected_response, response) def testStreamingInputCallFuture(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.StreamingInputCall.future( _streaming_input_request_iterator(test_pb2), test_constants.LONG_TIMEOUT) response = response_future.result() expected_response = methods.StreamingInputCall( _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!') self.assertEqual(expected_response, response) def testStreamingInputCallFutureExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.StreamingInputCall.future( _streaming_input_request_iterator(test_pb2), test_constants.SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): response_future.result() self.assertIsInstance( response_future.exception(), face.ExpirationError) def testStreamingInputCallFutureCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): with methods.pause(): response_future = stub.StreamingInputCall.future( _streaming_input_request_iterator(test_pb2), test_constants.LONG_TIMEOUT) response_future.cancel() self.assertTrue(response_future.cancelled()) with self.assertRaises(future.CancelledError): response_future.result() def testStreamingInputCallFutureFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): with methods.fail(): response_future = stub.StreamingInputCall.future( _streaming_input_request_iterator(test_pb2), test_constants.LONG_TIMEOUT) self.assertIsNotNone(response_future.exception()) def testFullDuplexCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): responses = stub.FullDuplexCall( _full_duplex_request_iterator(test_pb2), test_constants.LONG_TIMEOUT) expected_responses = methods.FullDuplexCall( _full_duplex_request_iterator(test_pb2), 'not a real RpcContext!') for expected_response, response in itertools.izip_longest( expected_responses, responses): self.assertEqual(expected_response, response) def testFullDuplexCallExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.pause(): responses = stub.FullDuplexCall( request_iterator, test_constants.SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(responses) def testFullDuplexCallCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): request_iterator = _full_duplex_request_iterator(test_pb2) responses = stub.FullDuplexCall( request_iterator, test_constants.LONG_TIMEOUT) next(responses) responses.cancel() with self.assertRaises(face.CancellationError): next(responses) def testFullDuplexCallFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2) as (methods, stub): with methods.fail(): responses = stub.FullDuplexCall( request_iterator, test_constants.LONG_TIMEOUT) self.assertIsNotNone(responses) with self.assertRaises(face.RemoteError): next(responses) def testHalfDuplexCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2) as (methods, stub): def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=2, interval_us=0) request.response_parameters.add(size=3, interval_us=0) yield request responses = stub.HalfDuplexCall( half_duplex_request_iterator(), test_constants.LONG_TIMEOUT) expected_responses = methods.HalfDuplexCall( half_duplex_request_iterator(), 'not a real RpcContext!') for check in itertools.izip_longest(expected_responses, responses): expected_response, response = check self.assertEqual(expected_response, response) def testHalfDuplexCallWedged(self): import test_pb2 # pylint: disable=g-import-not-at-top condition = threading.Condition() wait_cell = [False] @contextlib.contextmanager def wait(): # pylint: disable=invalid-name # Where's Python 3's 'nonlocal' statement when you need it? with condition: wait_cell[0] = True yield with condition: wait_cell[0] = False condition.notify_all() def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request with condition: while wait_cell[0]: condition.wait() with _CreateService(test_pb2) as (methods, stub): with wait(): responses = stub.HalfDuplexCall( half_duplex_request_iterator(), test_constants.SHORT_TIMEOUT) # half-duplex waits for the client to send all info with self.assertRaises(face.ExpirationError): next(responses) if __name__ == '__main__': os.chdir(os.path.dirname(sys.argv[0])) unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_protoc_plugin/alpha_python_plugin_test.py0000644000175000017500000005276712600663151030746 0ustar apollockapollock# 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. import argparse import contextlib import distutils.spawn import errno import itertools import os import pkg_resources import shutil import subprocess import sys import tempfile import threading import time import unittest from grpc.framework.alpha import exceptions from grpc.framework.foundation import future # Identifiers of entities we expect to find in the generated module. SERVICER_IDENTIFIER = 'EarlyAdopterTestServiceServicer' SERVER_IDENTIFIER = 'EarlyAdopterTestServiceServer' STUB_IDENTIFIER = 'EarlyAdopterTestServiceStub' SERVER_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_server' STUB_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_stub' # The timeout used in tests of RPCs that are supposed to expire. SHORT_TIMEOUT = 2 # The timeout used in tests of RPCs that are not supposed to expire. The # absurdly large value doesn't matter since no passing execution of this test # module will ever wait the duration. LONG_TIMEOUT = 600 NO_DELAY = 0 class _ServicerMethods(object): def __init__(self, test_pb2, delay): self._condition = threading.Condition() self._delay = delay self._paused = False self._fail = False self._test_pb2 = test_pb2 @contextlib.contextmanager def pause(self): # pylint: disable=invalid-name with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() @contextlib.contextmanager def fail(self): # pylint: disable=invalid-name with self._condition: self._fail = True yield with self._condition: self._fail = False def _control(self): # pylint: disable=invalid-name with self._condition: if self._fail: raise ValueError() while self._paused: self._condition.wait() time.sleep(self._delay) def UnaryCall(self, request, unused_rpc_context): response = self._test_pb2.SimpleResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * request.response_size self._control() return response def StreamingOutputCall(self, request, unused_rpc_context): for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() yield response def StreamingInputCall(self, request_iter, unused_rpc_context): response = self._test_pb2.StreamingInputCallResponse() aggregated_payload_size = 0 for request in request_iter: aggregated_payload_size += len(request.payload.payload_compressable) response.aggregated_payload_size = aggregated_payload_size self._control() return response def FullDuplexCall(self, request_iter, unused_rpc_context): for request in request_iter: for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() yield response def HalfDuplexCall(self, request_iter, unused_rpc_context): responses = [] for request in request_iter: for parameter in request.response_parameters: response = self._test_pb2.StreamingOutputCallResponse() response.payload.payload_type = self._test_pb2.COMPRESSABLE response.payload.payload_compressable = 'a' * parameter.size self._control() responses.append(response) for response in responses: yield response @contextlib.contextmanager def _CreateService(test_pb2, delay): """Provides a servicer backend and a stub. The servicer is just the implementation of the actual servicer passed to the face player of the python RPC implementation; the two are detached. Non-zero delay puts a delay on each call to the servicer, representative of communication latency. Timeout is the default timeout for the stub while waiting for the service. Args: test_pb2: The test_pb2 module generated by this test. delay: Delay in seconds per response from the servicer. Yields: A (servicer_methods, servicer, stub) three-tuple where servicer_methods is the back-end of the service bound to the stub and the server and stub are both activated and ready for use. """ servicer_methods = _ServicerMethods(test_pb2, delay) class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)): def UnaryCall(self, request, context): return servicer_methods.UnaryCall(request, context) def StreamingOutputCall(self, request, context): return servicer_methods.StreamingOutputCall(request, context) def StreamingInputCall(self, request_iter, context): return servicer_methods.StreamingInputCall(request_iter, context) def FullDuplexCall(self, request_iter, context): return servicer_methods.FullDuplexCall(request_iter, context) def HalfDuplexCall(self, request_iter, context): return servicer_methods.HalfDuplexCall(request_iter, context) servicer = Servicer() server = getattr( test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer, 0) with server: port = server.port() stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)('localhost', port) with stub: yield servicer_methods, stub, server def _streaming_input_request_iterator(test_pb2): for _ in range(3): request = test_pb2.StreamingInputCallRequest() request.payload.payload_type = test_pb2.COMPRESSABLE request.payload.payload_compressable = 'a' yield request def _streaming_output_request(test_pb2): request = test_pb2.StreamingOutputCallRequest() sizes = [1, 2, 3] request.response_parameters.add(size=sizes[0], interval_us=0) request.response_parameters.add(size=sizes[1], interval_us=0) request.response_parameters.add(size=sizes[2], interval_us=0) return request def _full_duplex_request_iterator(test_pb2): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=2, interval_us=0) request.response_parameters.add(size=3, interval_us=0) yield request class PythonPluginTest(unittest.TestCase): """Test case for the gRPC Python protoc-plugin. While reading these tests, remember that the futures API (`stub.method.async()`) only gives futures for the *non-streaming* responses, else it behaves like its blocking cousin. """ def setUp(self): # Assume that the appropriate protoc and grpc_python_plugins are on the # path. protoc_command = 'protoc' protoc_plugin_filename = distutils.spawn.find_executable( 'grpc_python_plugin') test_proto_filename = pkg_resources.resource_filename( 'grpc_protoc_plugin', 'test.proto') if not os.path.isfile(protoc_command): # Assume that if we haven't built protoc that it's on the system. protoc_command = 'protoc' # Ensure that the output directory exists. self.outdir = tempfile.mkdtemp() # Invoke protoc with the plugin. cmd = [ protoc_command, '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename, '-I .', '--python_out=%s' % self.outdir, '--python-grpc_out=%s' % self.outdir, os.path.basename(test_proto_filename), ] subprocess.check_call(' '.join(cmd), shell=True, env=os.environ, cwd=os.path.dirname(test_proto_filename)) sys.path.append(self.outdir) def tearDown(self): try: shutil.rmtree(self.outdir) except OSError as exc: if exc.errno != errno.ENOENT: raise # TODO(atash): Figure out which of these tests is hanging flakily with small # probability. def testImportAttributes(self): # check that we can access the generated module and its members. import test_pb2 # pylint: disable=g-import-not-at-top self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, SERVER_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None)) self.assertIsNotNone(getattr(test_pb2, STUB_FACTORY_IDENTIFIER, None)) def testUpDown(self): import test_pb2 with _CreateService( test_pb2, NO_DELAY) as (servicer, stub, unused_server): request = test_pb2.SimpleRequest(response_size=13) def testUnaryCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods. request = test_pb2.SimpleRequest(response_size=13) response = stub.UnaryCall(request, timeout) expected_response = methods.UnaryCall(request, 'not a real RpcContext!') self.assertEqual(expected_response, response) def testUnaryCallAsync(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): # Check that the call does not block waiting for the server to respond. with methods.pause(): response_future = stub.UnaryCall.async(request, LONG_TIMEOUT) response = response_future.result() expected_response = methods.UnaryCall(request, 'not a real RpcContext!') self.assertEqual(expected_response, response) def testUnaryCallAsyncExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): request = test_pb2.SimpleRequest(response_size=13) with methods.pause(): response_future = stub.UnaryCall.async(request, SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): response_future.result() @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testUnaryCallAsyncCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): response_future = stub.UnaryCall.async(request, 1) response_future.cancel() self.assertTrue(response_future.cancelled()) def testUnaryCallAsyncFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request = test_pb2.SimpleRequest(response_size=13) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): response_future = stub.UnaryCall.async(request, LONG_TIMEOUT) self.assertIsNotNone(response_future.exception()) def testStreamingOutputCall(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): responses = stub.StreamingOutputCall(request, LONG_TIMEOUT) expected_responses = methods.StreamingOutputCall( request, 'not a real RpcContext!') for expected_response, response in itertools.izip_longest( expected_responses, responses): self.assertEqual(expected_response, response) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testStreamingOutputCallExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testStreamingOutputCallCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( unused_methods, stub, unused_server): responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT) next(responses) responses.cancel() with self.assertRaises(future.CancelledError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this times out ' 'instead of raising the proper error.') def testStreamingOutputCallFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request = _streaming_output_request(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): responses = stub.StreamingOutputCall(request, 1) self.assertIsNotNone(responses) with self.assertRaises(exceptions.ServicerError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testStreamingInputCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): response = stub.StreamingInputCall( _streaming_input_request_iterator(test_pb2), LONG_TIMEOUT) expected_response = methods.StreamingInputCall( _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!') self.assertEqual(expected_response, response) def testStreamingInputCallAsync(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), LONG_TIMEOUT) response = response_future.result() expected_response = methods.StreamingInputCall( _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!') self.assertEqual(expected_response, response) def testStreamingInputCallAsyncExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): response_future.result() self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) def testStreamingInputCallAsyncCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods. response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), timeout) response_future.cancel() self.assertTrue(response_future.cancelled()) with self.assertRaises(future.CancelledError): response_future.result() def testStreamingInputCallAsyncFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): response_future = stub.StreamingInputCall.async( _streaming_input_request_iterator(test_pb2), SHORT_TIMEOUT) self.assertIsNotNone(response_future.exception()) def testFullDuplexCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): responses = stub.FullDuplexCall( _full_duplex_request_iterator(test_pb2), LONG_TIMEOUT) expected_responses = methods.FullDuplexCall( _full_duplex_request_iterator(test_pb2), 'not a real RpcContext!') for expected_response, response in itertools.izip_longest( expected_responses, responses): self.assertEqual(expected_response, response) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testFullDuplexCallExpired(self): import test_pb2 # pylint: disable=g-import-not-at-top request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.pause(): responses = stub.FullDuplexCall(request_iterator, SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testFullDuplexCallCancelled(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): request_iterator = _full_duplex_request_iterator(test_pb2) responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT) next(responses) responses.cancel() with self.assertRaises(future.CancelledError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this hangs forever ' 'and fix.') def testFullDuplexCallFailed(self): import test_pb2 # pylint: disable=g-import-not-at-top request_iterator = _full_duplex_request_iterator(test_pb2) with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): with methods.fail(): responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT) self.assertIsNotNone(responses) with self.assertRaises(exceptions.ServicerError): next(responses) @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs ' 'forever and fix.') def testHalfDuplexCall(self): import test_pb2 # pylint: disable=g-import-not-at-top with _CreateService(test_pb2, NO_DELAY) as ( methods, stub, unused_server): def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=2, interval_us=0) request.response_parameters.add(size=3, interval_us=0) yield request responses = stub.HalfDuplexCall( half_duplex_request_iterator(), LONG_TIMEOUT) expected_responses = methods.HalfDuplexCall( half_duplex_request_iterator(), 'not a real RpcContext!') for check in itertools.izip_longest(expected_responses, responses): expected_response, response = check self.assertEqual(expected_response, response) def testHalfDuplexCallWedged(self): import test_pb2 # pylint: disable=g-import-not-at-top condition = threading.Condition() wait_cell = [False] @contextlib.contextmanager def wait(): # pylint: disable=invalid-name # Where's Python 3's 'nonlocal' statement when you need it? with condition: wait_cell[0] = True yield with condition: wait_cell[0] = False condition.notify_all() def half_duplex_request_iterator(): request = test_pb2.StreamingOutputCallRequest() request.response_parameters.add(size=1, interval_us=0) yield request with condition: while wait_cell[0]: condition.wait() with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server): with wait(): responses = stub.HalfDuplexCall( half_duplex_request_iterator(), SHORT_TIMEOUT) # half-duplex waits for the client to send all info with self.assertRaises(exceptions.ExpirationError): next(responses) if __name__ == '__main__': os.chdir(os.path.dirname(sys.argv[0])) unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_protoc_plugin/test.proto0000644000175000017500000001223112600663151025313 0ustar apollockapollock// 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. // An integration test service that covers all the method signature permutations // of unary/streaming requests/responses. // This file is duplicated around the code base. See GitHub issue #526. syntax = "proto2"; package grpc.testing; enum PayloadType { // Compressable text format. COMPRESSABLE= 1; // Uncompressable binary format. UNCOMPRESSABLE = 2; // Randomly chosen from all other formats defined in this enum. RANDOM = 3; } message Payload { required PayloadType payload_type = 1; oneof payload_body { string payload_compressable = 2; bytes payload_uncompressable = 3; } } message SimpleRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, server randomly chooses one from other formats. optional PayloadType response_type = 1 [default=COMPRESSABLE]; // Desired payload size in the response from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. optional int32 response_size = 2; // Optional input payload sent along with the request. optional Payload payload = 3; } message SimpleResponse { optional Payload payload = 1; } message StreamingInputCallRequest { // Optional input payload sent along with the request. optional Payload payload = 1; // Not expecting any payload from the response. } message StreamingInputCallResponse { // Aggregated size of payloads received from the client. optional int32 aggregated_payload_size = 1; } message ResponseParameters { // Desired payload sizes in responses from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. required int32 size = 1; // Desired interval between consecutive responses in the response stream in // microseconds. required int32 interval_us = 2; } message StreamingOutputCallRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, the payload from each response in the stream // might be of different types. This is to simulate a mixed type of payload // stream. optional PayloadType response_type = 1 [default=COMPRESSABLE]; repeated ResponseParameters response_parameters = 2; // Optional input payload sent along with the request. optional Payload payload = 3; } message StreamingOutputCallResponse { optional Payload payload = 1; } service TestService { // One request followed by one response. // The server returns the client payload as-is. rpc UnaryCall(SimpleRequest) returns (SimpleResponse); // One request followed by a sequence of responses (streamed download). // The server returns the payload with client desired type and sizes. rpc StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); // A sequence of requests followed by one response (streamed upload). // The server returns the aggregated size of client payload as the result. rpc StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse); // A sequence of requests with each request served by the server immediately. // As one request could lead to multiple responses, this interface // demonstrates the idea of full duplexing. rpc FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); // A sequence of requests followed by a sequence of responses. // The server buffers all the client requests and then serves them in order. A // stream of responses are returned to the client when the server starts with // first request. rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); } grpc-0.11.1/src/python/grpcio_test/grpc_protoc_plugin/__init__.py0000644000175000017500000000277212600663151025371 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/0000755000175000017500000000000012600663151021343 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/_cython/0000755000175000017500000000000012600663151023006 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py0000644000175000017500000001777312600663151026737 0ustar apollockapollock# 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. # Fork of grpc._adapter._low_test; the grpc._cython.types adapter in # grpc._cython.low should transparently support the semantics expected of # grpc._adapter._low. import time import unittest from grpc._adapter import _types from grpc._cython import adapter_low as _low class InsecureServerInsecureClient(unittest.TestCase): def setUp(self): self.server_completion_queue = _low.CompletionQueue() self.server = _low.Server(self.server_completion_queue, []) self.port = self.server.add_http2_port('[::]:0') self.client_completion_queue = _low.CompletionQueue() self.client_channel = _low.Channel('localhost:%d'%self.port, []) self.server.start() def tearDown(self): self.server.shutdown() del self.client_channel self.client_completion_queue.shutdown() while (self.client_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN): pass self.server_completion_queue.shutdown() while (self.server_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN): pass del self.client_completion_queue del self.server_completion_queue del self.server @unittest.skip('TODO(atash): implement grpc._cython.adapter_low') def testEcho(self): DEADLINE = time.time()+5 DEADLINE_TOLERANCE = 0.25 CLIENT_METADATA_ASCII_KEY = 'key' CLIENT_METADATA_ASCII_VALUE = 'val' CLIENT_METADATA_BIN_KEY = 'key-bin' CLIENT_METADATA_BIN_VALUE = b'\0'*1000 SERVER_INITIAL_METADATA_KEY = 'init_me_me_me' SERVER_INITIAL_METADATA_VALUE = 'whodawha?' SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought' SERVER_TRAILING_METADATA_VALUE = 'zomg it is' SERVER_STATUS_CODE = _types.StatusCode.OK SERVER_STATUS_DETAILS = 'our work is never over' REQUEST = 'in death a member of project mayhem has a name' RESPONSE = 'his name is robert paulson' METHOD = 'twinkies' HOST = 'hostess' server_request_tag = object() request_call_result = self.server.request_call(self.server_completion_queue, server_request_tag) self.assertEqual(_types.CallError.OK, request_call_result) client_call_tag = object() client_call = self.client_channel.create_call(self.client_completion_queue, METHOD, HOST, DEADLINE) client_initial_metadata = [ (CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE), (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)] client_start_batch_result = client_call.start_batch([ _types.OpArgs.send_initial_metadata(client_initial_metadata), _types.OpArgs.send_message(REQUEST), _types.OpArgs.send_close_from_client(), _types.OpArgs.recv_initial_metadata(), _types.OpArgs.recv_message(), _types.OpArgs.recv_status_on_client() ], client_call_tag) self.assertEqual(_types.CallError.OK, client_start_batch_result) request_event = self.server_completion_queue.next(DEADLINE) self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type) self.assertIsInstance(request_event.call, _low.Call) self.assertIs(server_request_tag, request_event.tag) self.assertEqual(1, len(request_event.results)) self.assertEqual(dict(client_initial_metadata), dict(request_event.results[0].initial_metadata)) self.assertEqual(METHOD, request_event.call_details.method) self.assertEqual(HOST, request_event.call_details.host) self.assertLess(abs(DEADLINE - request_event.call_details.deadline), DEADLINE_TOLERANCE) server_call_tag = object() server_call = request_event.call server_initial_metadata = [ (SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)] server_trailing_metadata = [ (SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)] server_start_batch_result = server_call.start_batch([ _types.OpArgs.send_initial_metadata(server_initial_metadata), _types.OpArgs.recv_message(), _types.OpArgs.send_message(RESPONSE), _types.OpArgs.recv_close_on_server(), _types.OpArgs.send_status_from_server( server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS) ], server_call_tag) self.assertEqual(_types.CallError.OK, server_start_batch_result) client_event = self.client_completion_queue.next(DEADLINE) server_event = self.server_completion_queue.next(DEADLINE) self.assertEqual(6, len(client_event.results)) found_client_op_types = set() for client_result in client_event.results: # we expect each op type to be unique self.assertNotIn(client_result.type, found_client_op_types) found_client_op_types.add(client_result.type) if client_result.type == _types.OpType.RECV_INITIAL_METADATA: self.assertEqual(dict(server_initial_metadata), dict(client_result.initial_metadata)) elif client_result.type == _types.OpType.RECV_MESSAGE: self.assertEqual(RESPONSE, client_result.message) elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT: self.assertEqual(dict(server_trailing_metadata), dict(client_result.trailing_metadata)) self.assertEqual(SERVER_STATUS_DETAILS, client_result.status.details) self.assertEqual(SERVER_STATUS_CODE, client_result.status.code) self.assertEqual(set([ _types.OpType.SEND_INITIAL_METADATA, _types.OpType.SEND_MESSAGE, _types.OpType.SEND_CLOSE_FROM_CLIENT, _types.OpType.RECV_INITIAL_METADATA, _types.OpType.RECV_MESSAGE, _types.OpType.RECV_STATUS_ON_CLIENT ]), found_client_op_types) self.assertEqual(5, len(server_event.results)) found_server_op_types = set() for server_result in server_event.results: self.assertNotIn(client_result.type, found_server_op_types) found_server_op_types.add(server_result.type) if server_result.type == _types.OpType.RECV_MESSAGE: self.assertEqual(REQUEST, server_result.message) elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER: self.assertFalse(server_result.cancelled) self.assertEqual(set([ _types.OpType.SEND_INITIAL_METADATA, _types.OpType.RECV_MESSAGE, _types.OpType.SEND_MESSAGE, _types.OpType.RECV_CLOSE_ON_SERVER, _types.OpType.SEND_STATUS_FROM_SERVER ]), found_server_op_types) del client_call del server_call if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py0000644000175000017500000002577012600663151025721 0ustar apollockapollock# 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. import time import unittest from grpc._cython import cygrpc from grpc_test._cython import test_utilities class TypeSmokeTest(unittest.TestCase): def testStringsInUtilitiesUpDown(self): self.assertEqual(0, cygrpc.StatusCode.ok) metadatum = cygrpc.Metadatum('a', 'b') self.assertEqual('a'.encode(), metadatum.key) self.assertEqual('b'.encode(), metadatum.value) metadata = cygrpc.Metadata([metadatum]) self.assertEqual(1, len(metadata)) self.assertEqual(metadatum.key, metadata[0].key) def testMetadataIteration(self): metadata = cygrpc.Metadata([ cygrpc.Metadatum('a', 'b'), cygrpc.Metadatum('c', 'd')]) iterator = iter(metadata) metadatum = next(iterator) self.assertIsInstance(metadatum, cygrpc.Metadatum) self.assertEqual(metadatum.key, 'a'.encode()) self.assertEqual(metadatum.value, 'b'.encode()) metadatum = next(iterator) self.assertIsInstance(metadatum, cygrpc.Metadatum) self.assertEqual(metadatum.key, 'c'.encode()) self.assertEqual(metadatum.value, 'd'.encode()) with self.assertRaises(StopIteration): next(iterator) def testOperationsIteration(self): operations = cygrpc.Operations([ cygrpc.operation_send_message('asdf')]) iterator = iter(operations) operation = next(iterator) self.assertIsInstance(operation, cygrpc.Operation) # `Operation`s are write-only structures; can't directly debug anything out # of them. Just check that we stop iterating. with self.assertRaises(StopIteration): next(iterator) def testTimespec(self): now = time.time() timespec = cygrpc.Timespec(now) self.assertAlmostEqual(now, float(timespec), places=8) def testCompletionQueueUpDown(self): completion_queue = cygrpc.CompletionQueue() del completion_queue def testServerUpDown(self): server = cygrpc.Server(cygrpc.ChannelArgs([])) del server def testChannelUpDown(self): channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([])) del channel @unittest.skip('TODO(atash): undo skip after #2229 is merged') def testServerStartNoExplicitShutdown(self): server = cygrpc.Server() completion_queue = cygrpc.CompletionQueue() server.register_completion_queue(completion_queue) port = server.add_http2_port('[::]:0') self.assertIsInstance(port, int) server.start() del server @unittest.skip('TODO(atash): undo skip after #2229 is merged') def testServerStartShutdown(self): completion_queue = cygrpc.CompletionQueue() server = cygrpc.Server() server.add_http2_port('[::]:0') server.register_completion_queue(completion_queue) server.start() shutdown_tag = object() server.shutdown(completion_queue, shutdown_tag) event = completion_queue.poll() self.assertEqual(cygrpc.CompletionType.operation_complete, event.type) self.assertIs(shutdown_tag, event.tag) del server del completion_queue class InsecureServerInsecureClient(unittest.TestCase): def setUp(self): self.server_completion_queue = cygrpc.CompletionQueue() self.server = cygrpc.Server() self.server.register_completion_queue(self.server_completion_queue) self.port = self.server.add_http2_port('[::]:0') self.server.start() self.client_completion_queue = cygrpc.CompletionQueue() self.client_channel = cygrpc.Channel('localhost:{}'.format(self.port)) def tearDown(self): del self.server del self.client_completion_queue del self.server_completion_queue def testEcho(self): DEADLINE = time.time()+5 DEADLINE_TOLERANCE = 0.25 CLIENT_METADATA_ASCII_KEY = b'key' CLIENT_METADATA_ASCII_VALUE = b'val' CLIENT_METADATA_BIN_KEY = b'key-bin' CLIENT_METADATA_BIN_VALUE = b'\0'*1000 SERVER_INITIAL_METADATA_KEY = b'init_me_me_me' SERVER_INITIAL_METADATA_VALUE = b'whodawha?' SERVER_TRAILING_METADATA_KEY = b'California_is_in_a_drought' SERVER_TRAILING_METADATA_VALUE = b'zomg it is' SERVER_STATUS_CODE = cygrpc.StatusCode.ok SERVER_STATUS_DETAILS = b'our work is never over' REQUEST = b'in death a member of project mayhem has a name' RESPONSE = b'his name is robert paulson' METHOD = b'twinkies' HOST = b'hostess' cygrpc_deadline = cygrpc.Timespec(DEADLINE) server_request_tag = object() request_call_result = self.server.request_call( self.server_completion_queue, self.server_completion_queue, server_request_tag) self.assertEqual(cygrpc.CallError.ok, request_call_result) client_call_tag = object() client_call = self.client_channel.create_call(self.client_completion_queue, METHOD, HOST, cygrpc_deadline) client_initial_metadata = cygrpc.Metadata([ cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE), cygrpc.Metadatum(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]) client_start_batch_result = client_call.start_batch(cygrpc.Operations([ cygrpc.operation_send_initial_metadata(client_initial_metadata), cygrpc.operation_send_message(REQUEST), cygrpc.operation_send_close_from_client(), cygrpc.operation_receive_initial_metadata(), cygrpc.operation_receive_message(), cygrpc.operation_receive_status_on_client() ]), client_call_tag) self.assertEqual(cygrpc.CallError.ok, client_start_batch_result) client_event_future = test_utilities.CompletionQueuePollFuture( self.client_completion_queue, cygrpc_deadline) request_event = self.server_completion_queue.poll(cygrpc_deadline) self.assertEqual(cygrpc.CompletionType.operation_complete, request_event.type) self.assertIsInstance(request_event.operation_call, cygrpc.Call) self.assertIs(server_request_tag, request_event.tag) self.assertEqual(0, len(request_event.batch_operations)) self.assertEqual(dict(client_initial_metadata), dict(request_event.request_metadata)) self.assertEqual(METHOD, request_event.request_call_details.method) self.assertEqual(HOST, request_event.request_call_details.host) self.assertLess( abs(DEADLINE - float(request_event.request_call_details.deadline)), DEADLINE_TOLERANCE) server_call_tag = object() server_call = request_event.operation_call server_initial_metadata = cygrpc.Metadata([ cygrpc.Metadatum(SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]) server_trailing_metadata = cygrpc.Metadata([ cygrpc.Metadatum(SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)]) server_start_batch_result = server_call.start_batch([ cygrpc.operation_send_initial_metadata(server_initial_metadata), cygrpc.operation_receive_message(), cygrpc.operation_send_message(RESPONSE), cygrpc.operation_receive_close_on_server(), cygrpc.operation_send_status_from_server( server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS) ], server_call_tag) self.assertEqual(cygrpc.CallError.ok, server_start_batch_result) client_event = client_event_future.result() server_event = self.server_completion_queue.poll(cygrpc_deadline) self.assertEqual(6, len(client_event.batch_operations)) found_client_op_types = set() for client_result in client_event.batch_operations: # we expect each op type to be unique self.assertNotIn(client_result.type, found_client_op_types) found_client_op_types.add(client_result.type) if client_result.type == cygrpc.OperationType.receive_initial_metadata: self.assertEqual(dict(server_initial_metadata), dict(client_result.received_metadata)) elif client_result.type == cygrpc.OperationType.receive_message: self.assertEqual(RESPONSE, client_result.received_message.bytes()) elif client_result.type == cygrpc.OperationType.receive_status_on_client: self.assertEqual(dict(server_trailing_metadata), dict(client_result.received_metadata)) self.assertEqual(SERVER_STATUS_DETAILS, client_result.received_status_details) self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code) self.assertEqual(set([ cygrpc.OperationType.send_initial_metadata, cygrpc.OperationType.send_message, cygrpc.OperationType.send_close_from_client, cygrpc.OperationType.receive_initial_metadata, cygrpc.OperationType.receive_message, cygrpc.OperationType.receive_status_on_client ]), found_client_op_types) self.assertEqual(5, len(server_event.batch_operations)) found_server_op_types = set() for server_result in server_event.batch_operations: self.assertNotIn(client_result.type, found_server_op_types) found_server_op_types.add(server_result.type) if server_result.type == cygrpc.OperationType.receive_message: self.assertEqual(REQUEST, server_result.received_message.bytes()) elif server_result.type == cygrpc.OperationType.receive_close_on_server: self.assertFalse(server_result.received_cancelled) self.assertEqual(set([ cygrpc.OperationType.send_initial_metadata, cygrpc.OperationType.receive_message, cygrpc.OperationType.send_message, cygrpc.OperationType.receive_close_on_server, cygrpc.OperationType.send_status_from_server ]), found_server_op_types) del client_call del server_call if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_cython/test_utilities.py0000644000175000017500000000364712600663151026444 0ustar apollockapollock# 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. import threading from grpc._cython._cygrpc import completion_queue class CompletionQueuePollFuture: def __init__(self, completion_queue, deadline): def poller_function(): self._event_result = completion_queue.poll(deadline) self._event_result = None self._thread = threading.Thread(target=poller_function) self._thread.start() def result(self): self._thread.join() return self._event_result grpc-0.11.1/src/python/grpcio_test/grpc_test/_cython/__init__.py0000644000175000017500000000277012600663151025125 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/_cython/.gitignore0000644000175000017500000000004312600663151024773 0ustar apollockapollock*.h *.c *.a *.so *.dll *.pyc *.pyd grpc-0.11.1/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py0000644000175000017500000001406712600663151031320 0ustar apollockapollock# 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. """Tests Base interface compliance of the core-over-gRPC-links stack.""" import collections import logging import random import time import unittest from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc._links import service from grpc.beta import interfaces as beta_interfaces from grpc.framework.core import implementations from grpc.framework.interfaces.base import utilities from grpc_test import test_common as grpc_test_common from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.base import test_cases from grpc_test.framework.interfaces.base import test_interfaces class _SerializationBehaviors( collections.namedtuple( '_SerializationBehaviors', ('request_serializers', 'request_deserializers', 'response_serializers', 'response_deserializers',))): pass class _Links( collections.namedtuple( '_Links', ('invocation_end_link', 'invocation_grpc_link', 'service_grpc_link', 'service_end_link'))): pass def _serialization_behaviors_from_serializations(serializations): request_serializers = {} request_deserializers = {} response_serializers = {} response_deserializers = {} for (group, method), serialization in serializations.iteritems(): request_serializers[group, method] = serialization.serialize_request request_deserializers[group, method] = serialization.deserialize_request response_serializers[group, method] = serialization.serialize_response response_deserializers[group, method] = serialization.deserialize_response return _SerializationBehaviors( request_serializers, request_deserializers, response_serializers, response_deserializers) class _Implementation(test_interfaces.Implementation): def instantiate(self, serializations, servicer): serialization_behaviors = _serialization_behaviors_from_serializations( serializations) invocation_end_link = implementations.invocation_end_link() service_end_link = implementations.service_end_link( servicer, test_constants.DEFAULT_TIMEOUT, test_constants.MAXIMUM_TIMEOUT) service_grpc_link = service.service_link( serialization_behaviors.request_deserializers, serialization_behaviors.response_serializers) port = service_grpc_link.add_port('[::]:0', None) channel = _intermediary_low.Channel('localhost:%d' % port, None) invocation_grpc_link = invocation.invocation_link( channel, b'localhost', None, serialization_behaviors.request_serializers, serialization_behaviors.response_deserializers) invocation_end_link.join_link(invocation_grpc_link) invocation_grpc_link.join_link(invocation_end_link) service_end_link.join_link(service_grpc_link) service_grpc_link.join_link(service_end_link) invocation_grpc_link.start() service_grpc_link.start() return invocation_end_link, service_end_link, ( invocation_grpc_link, service_grpc_link) def destantiate(self, memo): invocation_grpc_link, service_grpc_link = memo invocation_grpc_link.stop() service_grpc_link.begin_stop() service_grpc_link.end_stop() def invocation_initial_metadata(self): return grpc_test_common.INVOCATION_INITIAL_METADATA def service_initial_metadata(self): return grpc_test_common.SERVICE_INITIAL_METADATA def invocation_completion(self): return utilities.completion(None, None, None) def service_completion(self): return utilities.completion( grpc_test_common.SERVICE_TERMINAL_METADATA, beta_interfaces.StatusCode.OK, grpc_test_common.DETAILS) def metadata_transmitted(self, original_metadata, transmitted_metadata): return original_metadata is None or grpc_test_common.metadata_transmitted( original_metadata, transmitted_metadata) def completion_transmitted(self, original_completion, transmitted_completion): if (original_completion.terminal_metadata is not None and not grpc_test_common.metadata_transmitted( original_completion.terminal_metadata, transmitted_completion.terminal_metadata)): return False elif original_completion.code is not transmitted_completion.code: return False elif original_completion.message != transmitted_completion.message: return False else: return True def load_tests(loader, tests, pattern): return unittest.TestSuite( tests=tuple( loader.loadTestsFromTestCase(test_case_class) for test_case_class in test_cases.test_cases(_Implementation()))) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/credentials/0000755000175000017500000000000012600663151023640 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/credentials/server1.pem0000755000175000017500000000170412600663151025737 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= -----END CERTIFICATE----- grpc-0.11.1/src/python/grpcio_test/grpc_test/credentials/ca.pem0000755000175000017500000000152712600663151024736 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 +L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG Dfcog5wrJytaQ6UA0wE= -----END CERTIFICATE----- grpc-0.11.1/src/python/grpcio_test/grpc_test/credentials/README0000644000175000017500000000006412600663151024520 0ustar apollockapollockThese are test keys *NOT* to be used in production. grpc-0.11.1/src/python/grpcio_test/grpc_test/credentials/server1.key0000755000175000017500000000162012600663151025743 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf 3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR 81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe F98XJ7tIFfJq -----END PRIVATE KEY----- grpc-0.11.1/src/python/grpcio_test/grpc_test/early_adopter/0000755000175000017500000000000012600663151024175 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/early_adopter/__init__.py0000644000175000017500000000277212600663151026316 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/early_adopter/implementations_test.py0000644000175000017500000001403012600663151031014 0ustar apollockapollock# 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. # TODO(nathaniel): Expand this test coverage. """Test of the GRPC-backed ForeLink and RearLink.""" import unittest from grpc.early_adopter import implementations from grpc.framework.alpha import utilities from grpc_test._junkdrawer import math_pb2 SERVICE_NAME = 'math.Math' DIV = 'Div' DIV_MANY = 'DivMany' FIB = 'Fib' SUM = 'Sum' def _fibbonacci(limit): left, right = 0, 1 for _ in xrange(limit): yield left left, right = right, left + right def _div(request, unused_context): return math_pb2.DivReply( quotient=request.dividend / request.divisor, remainder=request.dividend % request.divisor) def _div_many(request_iterator, unused_context): for request in request_iterator: yield math_pb2.DivReply( quotient=request.dividend / request.divisor, remainder=request.dividend % request.divisor) def _fib(request, unused_context): for number in _fibbonacci(request.limit): yield math_pb2.Num(num=number) def _sum(request_iterator, unused_context): accumulation = 0 for request in request_iterator: accumulation += request.num return math_pb2.Num(num=accumulation) _INVOCATION_DESCRIPTIONS = { DIV: utilities.unary_unary_invocation_description( math_pb2.DivArgs.SerializeToString, math_pb2.DivReply.FromString), DIV_MANY: utilities.stream_stream_invocation_description( math_pb2.DivArgs.SerializeToString, math_pb2.DivReply.FromString), FIB: utilities.unary_stream_invocation_description( math_pb2.FibArgs.SerializeToString, math_pb2.Num.FromString), SUM: utilities.stream_unary_invocation_description( math_pb2.Num.SerializeToString, math_pb2.Num.FromString), } _SERVICE_DESCRIPTIONS = { DIV: utilities.unary_unary_service_description( _div, math_pb2.DivArgs.FromString, math_pb2.DivReply.SerializeToString), DIV_MANY: utilities.stream_stream_service_description( _div_many, math_pb2.DivArgs.FromString, math_pb2.DivReply.SerializeToString), FIB: utilities.unary_stream_service_description( _fib, math_pb2.FibArgs.FromString, math_pb2.Num.SerializeToString), SUM: utilities.stream_unary_service_description( _sum, math_pb2.Num.FromString, math_pb2.Num.SerializeToString), } _TIMEOUT = 3 class EarlyAdopterImplementationsTest(unittest.TestCase): def setUp(self): self.server = implementations.server( SERVICE_NAME, _SERVICE_DESCRIPTIONS, 0) self.server.start() port = self.server.port() self.stub = implementations.stub( SERVICE_NAME, _INVOCATION_DESCRIPTIONS, 'localhost', port) def tearDown(self): self.server.stop() def testUpAndDown(self): with self.stub: pass def testUnaryUnary(self): divisor = 59 dividend = 973 expected_quotient = dividend / divisor expected_remainder = dividend % divisor with self.stub: response = self.stub.Div( math_pb2.DivArgs(divisor=divisor, dividend=dividend), _TIMEOUT) self.assertEqual(expected_quotient, response.quotient) self.assertEqual(expected_remainder, response.remainder) def testUnaryStream(self): stream_length = 43 with self.stub: response_iterator = self.stub.Fib( math_pb2.FibArgs(limit=stream_length), _TIMEOUT) numbers = tuple(response.num for response in response_iterator) for early, middle, later in zip(numbers, numbers[:1], numbers[:2]): self.assertEqual(early + middle, later) self.assertEqual(stream_length, len(numbers)) def testStreamUnary(self): stream_length = 127 with self.stub: response_future = self.stub.Sum.async( (math_pb2.Num(num=index) for index in range(stream_length)), _TIMEOUT) self.assertEqual( (stream_length * (stream_length - 1)) / 2, response_future.result().num) def testStreamStream(self): stream_length = 179 divisor_offset = 71 dividend_offset = 1763 with self.stub: response_iterator = self.stub.DivMany( (math_pb2.DivArgs( divisor=divisor_offset + index, dividend=dividend_offset + index) for index in range(stream_length)), _TIMEOUT) for index, response in enumerate(response_iterator): self.assertEqual( (dividend_offset + index) / (divisor_offset + index), response.quotient) self.assertEqual( (dividend_offset + index) % (divisor_offset + index), response.remainder) self.assertEqual(stream_length, index + 1) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/resources.py0000644000175000017500000000427612600663151023740 0ustar apollockapollock# 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. """Constants and functions for data used in interoperability testing.""" import os import pkg_resources _ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem' _PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key' _CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem' def test_root_certificates(): return pkg_resources.resource_string( __name__, _ROOT_CERTIFICATES_RESOURCE_PATH) def prod_root_certificates(): return open(os.environ['SSL_CERT_FILE'], mode='rb').read() def private_key(): return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH) def certificate_chain(): return pkg_resources.resource_string( __name__, _CERTIFICATE_CHAIN_RESOURCE_PATH) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/0000755000175000017500000000000012600663151023340 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/core/0000755000175000017500000000000012600663151024270 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/core/__init__.py0000644000175000017500000000277212600663151026411 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py0000644000175000017500000000724712600663151031004 0ustar apollockapollock# 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. """Tests the RPC Framework Core's implementation of the Base interface.""" import logging import random import time import unittest from grpc.framework.core import implementations from grpc.framework.interfaces.base import utilities from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.base import test_cases from grpc_test.framework.interfaces.base import test_interfaces class _Implementation(test_interfaces.Implementation): def __init__(self): self._invocation_initial_metadata = object() self._service_initial_metadata = object() self._invocation_terminal_metadata = object() self._service_terminal_metadata = object() def instantiate(self, serializations, servicer): invocation = implementations.invocation_end_link() service = implementations.service_end_link( servicer, test_constants.DEFAULT_TIMEOUT, test_constants.MAXIMUM_TIMEOUT) invocation.join_link(service) service.join_link(invocation) return invocation, service, None def destantiate(self, memo): pass def invocation_initial_metadata(self): return self._invocation_initial_metadata def service_initial_metadata(self): return self._service_initial_metadata def invocation_completion(self): return utilities.completion(self._invocation_terminal_metadata, None, None) def service_completion(self): return utilities.completion(self._service_terminal_metadata, None, None) def metadata_transmitted(self, original_metadata, transmitted_metadata): return transmitted_metadata is original_metadata def completion_transmitted(self, original_completion, transmitted_completion): return ( (original_completion.terminal_metadata is transmitted_completion.terminal_metadata) and original_completion.code is transmitted_completion.code and original_completion.message is transmitted_completion.message ) def load_tests(loader, tests, pattern): return unittest.TestSuite( tests=tuple( loader.loadTestsFromTestCase(test_case_class) for test_case_class in test_cases.test_cases(_Implementation()))) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/0000755000175000017500000000000012600663151025463 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/links/0000755000175000017500000000000012600663151026603 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py0000644000175000017500000001302712600663151032232 0ustar apollockapollock# 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. """State and behavior appropriate for use in tests.""" import logging import threading import time from grpc.framework.interfaces.links import links from grpc.framework.interfaces.links import utilities # A more-or-less arbitrary limit on the length of raw data values to be logged. _UNCOMFORTABLY_LONG = 48 def _safe_for_log_ticket(ticket): """Creates a safe-for-printing-to-the-log ticket for a given ticket. Args: ticket: Any links.Ticket. Returns: A links.Ticket that is as much as can be equal to the given ticket but possibly features values like the string "" in place of the actual values of the given ticket. """ if isinstance(ticket.payload, (basestring,)): payload_length = len(ticket.payload) else: payload_length = -1 if payload_length < _UNCOMFORTABLY_LONG: return ticket else: return links.Ticket( ticket.operation_id, ticket.sequence_number, ticket.group, ticket.method, ticket.subscription, ticket.timeout, ticket.allowance, ticket.initial_metadata, ''.format(payload_length), ticket.terminal_metadata, ticket.code, ticket.message, ticket.termination, None) class RecordingLink(links.Link): """A Link that records every ticket passed to it.""" def __init__(self): self._condition = threading.Condition() self._tickets = [] def accept_ticket(self, ticket): with self._condition: self._tickets.append(ticket) self._condition.notify_all() def join_link(self, link): pass def block_until_tickets_satisfy(self, predicate): """Blocks until the received tickets satisfy the given predicate. Args: predicate: A callable that takes a sequence of tickets and returns a boolean value. """ with self._condition: while not predicate(self._tickets): self._condition.wait() def tickets(self): """Returns a copy of the list of all tickets received by this Link.""" with self._condition: return tuple(self._tickets) class _Pipe(object): """A conduit that logs all tickets passed through it.""" def __init__(self, name): self._lock = threading.Lock() self._name = name self._left_mate = utilities.NULL_LINK self._right_mate = utilities.NULL_LINK def accept_left_to_right_ticket(self, ticket): with self._lock: logging.warning( '%s: moving left to right through %s: %s', time.time(), self._name, _safe_for_log_ticket(ticket)) try: self._right_mate.accept_ticket(ticket) except Exception as e: # pylint: disable=broad-except logging.exception(e) def accept_right_to_left_ticket(self, ticket): with self._lock: logging.warning( '%s: moving right to left through %s: %s', time.time(), self._name, _safe_for_log_ticket(ticket)) try: self._left_mate.accept_ticket(ticket) except Exception as e: # pylint: disable=broad-except logging.exception(e) def join_left_mate(self, left_mate): with self._lock: self._left_mate = utilities.NULL_LINK if left_mate is None else left_mate def join_right_mate(self, right_mate): with self._lock: self._right_mate = ( utilities.NULL_LINK if right_mate is None else right_mate) class _Facade(links.Link): def __init__(self, accept, join): self._accept = accept self._join = join def accept_ticket(self, ticket): self._accept(ticket) def join_link(self, link): self._join(link) def logging_links(name): """Creates a conduit that logs all tickets passed through it. Args: name: A name to use for the conduit to identify itself in logging output. Returns: Two links.Links, the first of which is the "left" side of the conduit and the second of which is the "right" side of the conduit. """ pipe = _Pipe(name) left_facade = _Facade(pipe.accept_left_to_right_ticket, pipe.join_left_mate) right_facade = _Facade(pipe.accept_right_to_left_ticket, pipe.join_right_mate) return left_facade, right_facade grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py0000644000175000017500000000277212600663151030724 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py0000644000175000017500000003023312600663151031313 0ustar apollockapollock# 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. """Tests of the links interface of RPC Framework.""" # unittest is referenced from specification in this module. import abc import unittest # pylint: disable=unused-import from grpc.framework.interfaces.links import links from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.links import test_utilities def at_least_n_payloads_received_predicate(n): def predicate(ticket_sequence): payload_count = 0 for ticket in ticket_sequence: if ticket.payload is not None: payload_count += 1 if n <= payload_count: return True else: return False return predicate def terminated(ticket_sequence): return ticket_sequence and ticket_sequence[-1].termination is not None _TRANSMISSION_GROUP = 'test.Group' _TRANSMISSION_METHOD = 'TestMethod' class TransmissionTest(object): """Tests ticket transmission between two connected links. This class must be mixed into a unittest.TestCase that implements the abstract methods it provides. """ __metaclass__ = abc.ABCMeta # This is a unittest.TestCase mix-in. # pylint: disable=invalid-name @abc.abstractmethod def create_transmitting_links(self): """Creates two connected links for use in this test. Returns: Two links.Links, the first of which will be used on the invocation side of RPCs and the second of which will be used on the service side of RPCs. """ raise NotImplementedError() @abc.abstractmethod def destroy_transmitting_links(self, invocation_side_link, service_side_link): """Destroys the two connected links created for this test. Args: invocation_side_link: The link used on the invocation side of RPCs in this test. service_side_link: The link used on the service side of RPCs in this test. """ raise NotImplementedError() @abc.abstractmethod def create_invocation_initial_metadata(self): """Creates a value for use as invocation-side initial metadata. Returns: A metadata value appropriate for use as invocation-side initial metadata or None if invocation-side initial metadata transmission is not supported by the links under test. """ raise NotImplementedError() @abc.abstractmethod def create_invocation_terminal_metadata(self): """Creates a value for use as invocation-side terminal metadata. Returns: A metadata value appropriate for use as invocation-side terminal metadata or None if invocation-side terminal metadata transmission is not supported by the links under test. """ raise NotImplementedError() @abc.abstractmethod def create_service_initial_metadata(self): """Creates a value for use as service-side initial metadata. Returns: A metadata value appropriate for use as service-side initial metadata or None if service-side initial metadata transmission is not supported by the links under test. """ raise NotImplementedError() @abc.abstractmethod def create_service_terminal_metadata(self): """Creates a value for use as service-side terminal metadata. Returns: A metadata value appropriate for use as service-side terminal metadata or None if service-side terminal metadata transmission is not supported by the links under test. """ raise NotImplementedError() @abc.abstractmethod def create_invocation_completion(self): """Creates values for use as invocation-side code and message. Returns: An invocation-side code value and an invocation-side message value. Either or both may be None if invocation-side code and/or invocation-side message transmission is not supported by the links under test. """ raise NotImplementedError() @abc.abstractmethod def create_service_completion(self): """Creates values for use as service-side code and message. Returns: A service-side code value and a service-side message value. Either or both may be None if service-side code and/or service-side message transmission is not supported by the links under test. """ raise NotImplementedError() @abc.abstractmethod def assertMetadataTransmitted(self, original_metadata, transmitted_metadata): """Asserts that transmitted_metadata contains original_metadata. Args: original_metadata: A metadata object used in this test. transmitted_metadata: A metadata object obtained after transmission through the system under test. Raises: AssertionError: if the transmitted_metadata object does not contain original_metadata. """ raise NotImplementedError() def group_and_method(self): """Returns the group and method used in this test case. Returns: A pair of the group and method used in this test case. """ return _TRANSMISSION_GROUP, _TRANSMISSION_METHOD def serialize_request(self, request): """Serializes a request value used in this test case. Args: request: A request value created by this test case. Returns: A bytestring that is the serialization of the given request. """ return request def deserialize_request(self, serialized_request): """Deserializes a request value used in this test case. Args: serialized_request: A bytestring that is the serialization of some request used in this test case. Returns: The request value encoded by the given bytestring. """ return serialized_request def serialize_response(self, response): """Serializes a response value used in this test case. Args: response: A response value created by this test case. Returns: A bytestring that is the serialization of the given response. """ return response def deserialize_response(self, serialized_response): """Deserializes a response value used in this test case. Args: serialized_response: A bytestring that is the serialization of some response used in this test case. Returns: The response value encoded by the given bytestring. """ return serialized_response def _assert_is_valid_metadata_payload_sequence( self, ticket_sequence, payloads, initial_metadata, terminal_metadata): initial_metadata_seen = False seen_payloads = [] terminal_metadata_seen = False for ticket in ticket_sequence: if ticket.initial_metadata is not None: self.assertFalse(initial_metadata_seen) self.assertFalse(seen_payloads) self.assertFalse(terminal_metadata_seen) self.assertMetadataTransmitted(initial_metadata, ticket.initial_metadata) initial_metadata_seen = True if ticket.payload is not None: self.assertFalse(terminal_metadata_seen) seen_payloads.append(ticket.payload) if ticket.terminal_metadata is not None: self.assertFalse(terminal_metadata_seen) self.assertMetadataTransmitted(terminal_metadata, ticket.terminal_metadata) terminal_metadata_seen = True self.assertSequenceEqual(payloads, seen_payloads) def _assert_is_valid_invocation_sequence( self, ticket_sequence, group, method, payloads, initial_metadata, terminal_metadata, termination): self.assertLess(0, len(ticket_sequence)) self.assertEqual(group, ticket_sequence[0].group) self.assertEqual(method, ticket_sequence[0].method) self._assert_is_valid_metadata_payload_sequence( ticket_sequence, payloads, initial_metadata, terminal_metadata) self.assertIs(termination, ticket_sequence[-1].termination) def _assert_is_valid_service_sequence( self, ticket_sequence, payloads, initial_metadata, terminal_metadata, code, message, termination): self.assertLess(0, len(ticket_sequence)) self._assert_is_valid_metadata_payload_sequence( ticket_sequence, payloads, initial_metadata, terminal_metadata) self.assertEqual(code, ticket_sequence[-1].code) self.assertEqual(message, ticket_sequence[-1].message) self.assertIs(termination, ticket_sequence[-1].termination) def setUp(self): self._invocation_link, self._service_link = self.create_transmitting_links() self._invocation_mate = test_utilities.RecordingLink() self._service_mate = test_utilities.RecordingLink() self._invocation_link.join_link(self._invocation_mate) self._service_link.join_link(self._service_mate) def tearDown(self): self.destroy_transmitting_links(self._invocation_link, self._service_link) def testSimplestRoundTrip(self): """Tests transmission of one ticket in each direction.""" invocation_operation_id = object() invocation_payload = b'\x07' * 1023 timeout = test_constants.LONG_TIMEOUT invocation_initial_metadata = self.create_invocation_initial_metadata() invocation_terminal_metadata = self.create_invocation_terminal_metadata() invocation_code, invocation_message = self.create_invocation_completion() service_payload = b'\x08' * 1025 service_initial_metadata = self.create_service_initial_metadata() service_terminal_metadata = self.create_service_terminal_metadata() service_code, service_message = self.create_service_completion() original_invocation_ticket = links.Ticket( invocation_operation_id, 0, _TRANSMISSION_GROUP, _TRANSMISSION_METHOD, links.Ticket.Subscription.FULL, timeout, 0, invocation_initial_metadata, invocation_payload, invocation_terminal_metadata, invocation_code, invocation_message, links.Ticket.Termination.COMPLETION, None) self._invocation_link.accept_ticket(original_invocation_ticket) self._service_mate.block_until_tickets_satisfy( at_least_n_payloads_received_predicate(1)) service_operation_id = self._service_mate.tickets()[0].operation_id self._service_mate.block_until_tickets_satisfy(terminated) self._assert_is_valid_invocation_sequence( self._service_mate.tickets(), _TRANSMISSION_GROUP, _TRANSMISSION_METHOD, (invocation_payload,), invocation_initial_metadata, invocation_terminal_metadata, links.Ticket.Termination.COMPLETION) original_service_ticket = links.Ticket( service_operation_id, 0, None, None, links.Ticket.Subscription.FULL, timeout, 0, service_initial_metadata, service_payload, service_terminal_metadata, service_code, service_message, links.Ticket.Termination.COMPLETION, None) self._service_link.accept_ticket(original_service_ticket) self._invocation_mate.block_until_tickets_satisfy(terminated) self._assert_is_valid_service_sequence( self._invocation_mate.tickets(), (service_payload,), service_initial_metadata, service_terminal_metadata, service_code, service_message, links.Ticket.Termination.COMPLETION) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/0000755000175000017500000000000012600663151026361 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py0000644000175000017500000003635312600663151030363 0ustar apollockapollock# 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. """Code for making a service.TestService more amenable to use in tests.""" import collections import threading # test_control, _service, and test_interfaces are referenced from specification # in this module. from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_control # pylint: disable=unused-import from grpc_test.framework.interfaces.face import _service # pylint: disable=unused-import from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import _IDENTITY = lambda x: x class TestServiceDigest( collections.namedtuple( 'TestServiceDigest', ('methods', 'inline_method_implementations', 'event_method_implementations', 'multi_method_implementation', 'unary_unary_messages_sequences', 'unary_stream_messages_sequences', 'stream_unary_messages_sequences', 'stream_stream_messages_sequences',))): """A transformation of a service.TestService. Attributes: methods: A dict from method group-name pair to test_interfaces.Method object describing the RPC methods that may be called during the test. inline_method_implementations: A dict from method group-name pair to face.MethodImplementation object to be used in tests of in-line calls to behaviors under test. event_method_implementations: A dict from method group-name pair to face.MethodImplementation object to be used in tests of event-driven calls to behaviors under test. multi_method_implementation: A face.MultiMethodImplementation to be used in tests of generic calls to behaviors under test. unary_unary_messages_sequences: A dict from method group-name pair to sequence of service.UnaryUnaryTestMessages objects to be used to test the identified method. unary_stream_messages_sequences: A dict from method group-name pair to sequence of service.UnaryStreamTestMessages objects to be used to test the identified method. stream_unary_messages_sequences: A dict from method group-name pair to sequence of service.StreamUnaryTestMessages objects to be used to test the identified method. stream_stream_messages_sequences: A dict from method group-name pair to sequence of service.StreamStreamTestMessages objects to be used to test the identified method. """ class _BufferingConsumer(stream.Consumer): """A trivial Consumer that dumps what it consumes in a user-mutable buffer.""" def __init__(self): self.consumed = [] self.terminated = False def consume(self, value): self.consumed.append(value) def terminate(self): self.terminated = True def consume_and_terminate(self, value): self.consumed.append(value) self.terminated = True class _InlineUnaryUnaryMethod(face.MethodImplementation): def __init__(self, unary_unary_test_method, control): self._test_method = unary_unary_test_method self._control = control self.cardinality = cardinality.Cardinality.UNARY_UNARY self.style = style.Service.INLINE def unary_unary_inline(self, request, context): response_list = [] self._test_method.service( request, response_list.append, context, self._control) return response_list.pop(0) class _EventUnaryUnaryMethod(face.MethodImplementation): def __init__(self, unary_unary_test_method, control, pool): self._test_method = unary_unary_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.UNARY_UNARY self.style = style.Service.EVENT def unary_unary_event(self, request, response_callback, context): if self._pool is None: self._test_method.service( request, response_callback, context, self._control) else: self._pool.submit( self._test_method.service, request, response_callback, context, self._control) class _InlineUnaryStreamMethod(face.MethodImplementation): def __init__(self, unary_stream_test_method, control): self._test_method = unary_stream_test_method self._control = control self.cardinality = cardinality.Cardinality.UNARY_STREAM self.style = style.Service.INLINE def unary_stream_inline(self, request, context): response_consumer = _BufferingConsumer() self._test_method.service( request, response_consumer, context, self._control) for response in response_consumer.consumed: yield response class _EventUnaryStreamMethod(face.MethodImplementation): def __init__(self, unary_stream_test_method, control, pool): self._test_method = unary_stream_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.UNARY_STREAM self.style = style.Service.EVENT def unary_stream_event(self, request, response_consumer, context): if self._pool is None: self._test_method.service( request, response_consumer, context, self._control) else: self._pool.submit( self._test_method.service, request, response_consumer, context, self._control) class _InlineStreamUnaryMethod(face.MethodImplementation): def __init__(self, stream_unary_test_method, control): self._test_method = stream_unary_test_method self._control = control self.cardinality = cardinality.Cardinality.STREAM_UNARY self.style = style.Service.INLINE def stream_unary_inline(self, request_iterator, context): response_list = [] request_consumer = self._test_method.service( response_list.append, context, self._control) for request in request_iterator: request_consumer.consume(request) request_consumer.terminate() return response_list.pop(0) class _EventStreamUnaryMethod(face.MethodImplementation): def __init__(self, stream_unary_test_method, control, pool): self._test_method = stream_unary_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.STREAM_UNARY self.style = style.Service.EVENT def stream_unary_event(self, response_callback, context): request_consumer = self._test_method.service( response_callback, context, self._control) if self._pool is None: return request_consumer else: return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool) class _InlineStreamStreamMethod(face.MethodImplementation): def __init__(self, stream_stream_test_method, control): self._test_method = stream_stream_test_method self._control = control self.cardinality = cardinality.Cardinality.STREAM_STREAM self.style = style.Service.INLINE def stream_stream_inline(self, request_iterator, context): response_consumer = _BufferingConsumer() request_consumer = self._test_method.service( response_consumer, context, self._control) for request in request_iterator: request_consumer.consume(request) while response_consumer.consumed: yield response_consumer.consumed.pop(0) response_consumer.terminate() class _EventStreamStreamMethod(face.MethodImplementation): def __init__(self, stream_stream_test_method, control, pool): self._test_method = stream_stream_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.STREAM_STREAM self.style = style.Service.EVENT def stream_stream_event(self, response_consumer, context): request_consumer = self._test_method.service( response_consumer, context, self._control) if self._pool is None: return request_consumer else: return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool) class _UnaryConsumer(stream.Consumer): """A Consumer that only allows consumption of exactly one value.""" def __init__(self, action): self._lock = threading.Lock() self._action = action self._consumed = False self._terminated = False def consume(self, value): with self._lock: if self._consumed: raise ValueError('Unary consumer already consumed!') elif self._terminated: raise ValueError('Unary consumer already terminated!') else: self._consumed = True self._action(value) def terminate(self): with self._lock: if not self._consumed: raise ValueError('Unary consumer hasn\'t yet consumed!') elif self._terminated: raise ValueError('Unary consumer already terminated!') else: self._terminated = True def consume_and_terminate(self, value): with self._lock: if self._consumed: raise ValueError('Unary consumer already consumed!') elif self._terminated: raise ValueError('Unary consumer already terminated!') else: self._consumed = True self._terminated = True self._action(value) class _UnaryUnaryAdaptation(object): def __init__(self, unary_unary_test_method): self._method = unary_unary_test_method def service(self, response_consumer, context, control): def action(request): self._method.service( request, response_consumer.consume_and_terminate, context, control) return _UnaryConsumer(action) class _UnaryStreamAdaptation(object): def __init__(self, unary_stream_test_method): self._method = unary_stream_test_method def service(self, response_consumer, context, control): def action(request): self._method.service(request, response_consumer, context, control) return _UnaryConsumer(action) class _StreamUnaryAdaptation(object): def __init__(self, stream_unary_test_method): self._method = stream_unary_test_method def service(self, response_consumer, context, control): return self._method.service( response_consumer.consume_and_terminate, context, control) class _MultiMethodImplementation(face.MultiMethodImplementation): def __init__(self, methods, control, pool): self._methods = methods self._control = control self._pool = pool def service(self, group, name, response_consumer, context): method = self._methods.get(group, name, None) if method is None: raise face.NoSuchMethodError(group, name) elif self._pool is None: return method(response_consumer, context, self._control) else: request_consumer = method(response_consumer, context, self._control) return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool) class _Assembly( collections.namedtuple( '_Assembly', ['methods', 'inlines', 'events', 'adaptations', 'messages'])): """An intermediate structure created when creating a TestServiceDigest.""" def _assemble( scenarios, identifiers, inline_method_constructor, event_method_constructor, adapter, control, pool): """Creates an _Assembly from the given scenarios.""" methods = {} inlines = {} events = {} adaptations = {} messages = {} for identifier, scenario in scenarios.iteritems(): if identifier in identifiers: raise ValueError('Repeated identifier "(%s, %s)"!' % identifier) test_method = scenario[0] inline_method = inline_method_constructor(test_method, control) event_method = event_method_constructor(test_method, control, pool) adaptation = adapter(test_method) methods[identifier] = test_method inlines[identifier] = inline_method events[identifier] = event_method adaptations[identifier] = adaptation messages[identifier] = scenario[1] return _Assembly(methods, inlines, events, adaptations, messages) def digest(service, control, pool): """Creates a TestServiceDigest from a TestService. Args: service: A _service.TestService. control: A test_control.Control. pool: If RPC methods should be serviced in a separate thread, a thread pool. None if RPC methods should be serviced in the thread belonging to the run-time that calls for their service. Returns: A TestServiceDigest synthesized from the given service.TestService. """ identifiers = set() unary_unary = _assemble( service.unary_unary_scenarios(), identifiers, _InlineUnaryUnaryMethod, _EventUnaryUnaryMethod, _UnaryUnaryAdaptation, control, pool) identifiers.update(unary_unary.inlines) unary_stream = _assemble( service.unary_stream_scenarios(), identifiers, _InlineUnaryStreamMethod, _EventUnaryStreamMethod, _UnaryStreamAdaptation, control, pool) identifiers.update(unary_stream.inlines) stream_unary = _assemble( service.stream_unary_scenarios(), identifiers, _InlineStreamUnaryMethod, _EventStreamUnaryMethod, _StreamUnaryAdaptation, control, pool) identifiers.update(stream_unary.inlines) stream_stream = _assemble( service.stream_stream_scenarios(), identifiers, _InlineStreamStreamMethod, _EventStreamStreamMethod, _IDENTITY, control, pool) identifiers.update(stream_stream.inlines) methods = dict(unary_unary.methods) methods.update(unary_stream.methods) methods.update(stream_unary.methods) methods.update(stream_stream.methods) adaptations = dict(unary_unary.adaptations) adaptations.update(unary_stream.adaptations) adaptations.update(stream_unary.adaptations) adaptations.update(stream_stream.adaptations) inlines = dict(unary_unary.inlines) inlines.update(unary_stream.inlines) inlines.update(stream_unary.inlines) inlines.update(stream_stream.inlines) events = dict(unary_unary.events) events.update(unary_stream.events) events.update(stream_unary.events) events.update(stream_stream.events) return TestServiceDigest( methods, inlines, events, _MultiMethodImplementation(adaptations, control, pool), unary_unary.messages, unary_stream.messages, stream_unary.messages, stream_stream.messages) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py0000644000175000017500000001601212600663151031243 0ustar apollockapollock# 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. """Coverage across the Face layer's generic-to-dynamic range for invocation.""" import abc from grpc.framework.common import cardinality _CARDINALITY_TO_GENERIC_BLOCKING_BEHAVIOR = { cardinality.Cardinality.UNARY_UNARY: 'blocking_unary_unary', cardinality.Cardinality.UNARY_STREAM: 'inline_unary_stream', cardinality.Cardinality.STREAM_UNARY: 'blocking_stream_unary', cardinality.Cardinality.STREAM_STREAM: 'inline_stream_stream', } _CARDINALITY_TO_GENERIC_FUTURE_BEHAVIOR = { cardinality.Cardinality.UNARY_UNARY: 'future_unary_unary', cardinality.Cardinality.UNARY_STREAM: 'inline_unary_stream', cardinality.Cardinality.STREAM_UNARY: 'future_stream_unary', cardinality.Cardinality.STREAM_STREAM: 'inline_stream_stream', } _CARDINALITY_TO_GENERIC_EVENT_BEHAVIOR = { cardinality.Cardinality.UNARY_UNARY: 'event_unary_unary', cardinality.Cardinality.UNARY_STREAM: 'event_unary_stream', cardinality.Cardinality.STREAM_UNARY: 'event_stream_unary', cardinality.Cardinality.STREAM_STREAM: 'event_stream_stream', } _CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE = { cardinality.Cardinality.UNARY_UNARY: 'unary_unary', cardinality.Cardinality.UNARY_STREAM: 'unary_stream', cardinality.Cardinality.STREAM_UNARY: 'stream_unary', cardinality.Cardinality.STREAM_STREAM: 'stream_stream', } class Invoker(object): """A type used to invoke test RPCs.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def blocking(self, group, name): """Invokes an RPC with blocking control flow.""" raise NotImplementedError() @abc.abstractmethod def future(self, group, name): """Invokes an RPC with future control flow.""" raise NotImplementedError() @abc.abstractmethod def event(self, group, name): """Invokes an RPC with event control flow.""" raise NotImplementedError() class InvokerConstructor(object): """A type used to create Invokers.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def name(self): """Specifies the name of the Invoker constructed by this object.""" raise NotImplementedError() @abc.abstractmethod def construct_invoker(self, generic_stub, dynamic_stubs, methods): """Constructs an Invoker for the given stubs and methods.""" raise NotImplementedError() class _GenericInvoker(Invoker): def __init__(self, generic_stub, methods): self._stub = generic_stub self._methods = methods def _behavior(self, group, name, cardinality_to_generic_method): method_cardinality = self._methods[group, name].cardinality() behavior = getattr( self._stub, cardinality_to_generic_method[method_cardinality]) return lambda *args, **kwargs: behavior(group, name, *args, **kwargs) def blocking(self, group, name): return self._behavior( group, name, _CARDINALITY_TO_GENERIC_BLOCKING_BEHAVIOR) def future(self, group, name): return self._behavior(group, name, _CARDINALITY_TO_GENERIC_FUTURE_BEHAVIOR) def event(self, group, name): return self._behavior(group, name, _CARDINALITY_TO_GENERIC_EVENT_BEHAVIOR) class _GenericInvokerConstructor(InvokerConstructor): def name(self): return 'GenericInvoker' def construct_invoker(self, generic_stub, dynamic_stub, methods): return _GenericInvoker(generic_stub, methods) class _MultiCallableInvoker(Invoker): def __init__(self, generic_stub, methods): self._stub = generic_stub self._methods = methods def _multi_callable(self, group, name): method_cardinality = self._methods[group, name].cardinality() behavior = getattr( self._stub, _CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE[method_cardinality]) return behavior(group, name) def blocking(self, group, name): return self._multi_callable(group, name) def future(self, group, name): method_cardinality = self._methods[group, name].cardinality() behavior = getattr( self._stub, _CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE[method_cardinality]) if method_cardinality in ( cardinality.Cardinality.UNARY_UNARY, cardinality.Cardinality.STREAM_UNARY): return behavior(group, name).future else: return behavior(group, name) def event(self, group, name): return self._multi_callable(group, name).event class _MultiCallableInvokerConstructor(InvokerConstructor): def name(self): return 'MultiCallableInvoker' def construct_invoker(self, generic_stub, dynamic_stub, methods): return _MultiCallableInvoker(generic_stub, methods) class _DynamicInvoker(Invoker): def __init__(self, dynamic_stubs, methods): self._stubs = dynamic_stubs self._methods = methods def blocking(self, group, name): return getattr(self._stubs[group], name) def future(self, group, name): if self._methods[group, name].cardinality() in ( cardinality.Cardinality.UNARY_UNARY, cardinality.Cardinality.STREAM_UNARY): return getattr(self._stubs[group], name).future else: return getattr(self._stubs[group], name) def event(self, group, name): return getattr(self._stubs[group], name).event class _DynamicInvokerConstructor(InvokerConstructor): def name(self): return 'DynamicInvoker' def construct_invoker(self, generic_stub, dynamic_stubs, methods): return _DynamicInvoker(dynamic_stubs, methods) def invoker_constructors(): """Creates a sequence of InvokerConstructors to use in tests of RPCs. Returns: A sequence of InvokerConstructors. """ return ( _GenericInvokerConstructor(), _MultiCallableInvokerConstructor(), _DynamicInvokerConstructor(), ) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py0000644000175000017500000003107712600663151031745 0ustar apollockapollock# 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. """Examples of Python implementations of the stock.proto Stock service.""" from grpc.framework.common import cardinality from grpc.framework.foundation import abandonment from grpc.framework.foundation import stream from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.face import _service from grpc_test._junkdrawer import stock_pb2 _STOCK_GROUP_NAME = 'Stock' _SYMBOL_FORMAT = 'test symbol:%03d' # A test-appropriate security-pricing function. :-P _price = lambda symbol_name: float(hash(symbol_name) % 4096) def _get_last_trade_price(stock_request, stock_reply_callback, control, active): """A unary-request, unary-response test method.""" control.control() if active(): stock_reply_callback( stock_pb2.StockReply( symbol=stock_request.symbol, price=_price(stock_request.symbol))) else: raise abandonment.Abandoned() def _get_last_trade_price_multiple(stock_reply_consumer, control, active): """A stream-request, stream-response test method.""" def stock_reply_for_stock_request(stock_request): control.control() if active(): return stock_pb2.StockReply( symbol=stock_request.symbol, price=_price(stock_request.symbol)) else: raise abandonment.Abandoned() class StockRequestConsumer(stream.Consumer): def consume(self, stock_request): stock_reply_consumer.consume(stock_reply_for_stock_request(stock_request)) def terminate(self): control.control() stock_reply_consumer.terminate() def consume_and_terminate(self, stock_request): stock_reply_consumer.consume_and_terminate( stock_reply_for_stock_request(stock_request)) return StockRequestConsumer() def _watch_future_trades(stock_request, stock_reply_consumer, control, active): """A unary-request, stream-response test method.""" base_price = _price(stock_request.symbol) for index in range(stock_request.num_trades_to_watch): control.control() if active(): stock_reply_consumer.consume( stock_pb2.StockReply( symbol=stock_request.symbol, price=base_price + index)) else: raise abandonment.Abandoned() stock_reply_consumer.terminate() def _get_highest_trade_price(stock_reply_callback, control, active): """A stream-request, unary-response test method.""" class StockRequestConsumer(stream.Consumer): """Keeps an ongoing record of the most valuable symbol yet consumed.""" def __init__(self): self._symbol = None self._price = None def consume(self, stock_request): control.control() if active(): if self._price is None: self._symbol = stock_request.symbol self._price = _price(stock_request.symbol) else: candidate_price = _price(stock_request.symbol) if self._price < candidate_price: self._symbol = stock_request.symbol self._price = candidate_price def terminate(self): control.control() if active(): if self._symbol is None: raise ValueError() else: stock_reply_callback( stock_pb2.StockReply(symbol=self._symbol, price=self._price)) self._symbol = None self._price = None def consume_and_terminate(self, stock_request): control.control() if active(): if self._price is None: stock_reply_callback( stock_pb2.StockReply( symbol=stock_request.symbol, price=_price(stock_request.symbol))) else: candidate_price = _price(stock_request.symbol) if self._price < candidate_price: stock_reply_callback( stock_pb2.StockReply( symbol=stock_request.symbol, price=candidate_price)) else: stock_reply_callback( stock_pb2.StockReply( symbol=self._symbol, price=self._price)) self._symbol = None self._price = None return StockRequestConsumer() class GetLastTradePrice(_service.UnaryUnaryTestMethodImplementation): """GetLastTradePrice for use in tests.""" def group(self): return _STOCK_GROUP_NAME def name(self): return 'GetLastTradePrice' def cardinality(self): return cardinality.Cardinality.UNARY_UNARY def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, request, response_callback, context, control): _get_last_trade_price( request, response_callback, control, context.is_active) class GetLastTradePriceMessages(_service.UnaryUnaryTestMessages): def __init__(self): self._index = 0 def request(self): symbol = _SYMBOL_FORMAT % self._index self._index += 1 return stock_pb2.StockRequest(symbol=symbol) def verify(self, request, response, test_case): test_case.assertEqual(request.symbol, response.symbol) test_case.assertEqual(_price(request.symbol), response.price) class GetLastTradePriceMultiple(_service.StreamStreamTestMethodImplementation): """GetLastTradePriceMultiple for use in tests.""" def group(self): return _STOCK_GROUP_NAME def name(self): return 'GetLastTradePriceMultiple' def cardinality(self): return cardinality.Cardinality.STREAM_STREAM def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, response_consumer, context, control): return _get_last_trade_price_multiple( response_consumer, control, context.is_active) class GetLastTradePriceMultipleMessages(_service.StreamStreamTestMessages): """Pairs of message streams for use with GetLastTradePriceMultiple.""" def __init__(self): self._index = 0 def requests(self): base_index = self._index self._index += 1 return [ stock_pb2.StockRequest(symbol=_SYMBOL_FORMAT % (base_index + index)) for index in range(test_constants.STREAM_LENGTH)] def verify(self, requests, responses, test_case): test_case.assertEqual(len(requests), len(responses)) for stock_request, stock_reply in zip(requests, responses): test_case.assertEqual(stock_request.symbol, stock_reply.symbol) test_case.assertEqual(_price(stock_request.symbol), stock_reply.price) class WatchFutureTrades(_service.UnaryStreamTestMethodImplementation): """WatchFutureTrades for use in tests.""" def group(self): return _STOCK_GROUP_NAME def name(self): return 'WatchFutureTrades' def cardinality(self): return cardinality.Cardinality.UNARY_STREAM def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, request, response_consumer, context, control): _watch_future_trades(request, response_consumer, control, context.is_active) class WatchFutureTradesMessages(_service.UnaryStreamTestMessages): """Pairs of a single request message and a sequence of response messages.""" def __init__(self): self._index = 0 def request(self): symbol = _SYMBOL_FORMAT % self._index self._index += 1 return stock_pb2.StockRequest( symbol=symbol, num_trades_to_watch=test_constants.STREAM_LENGTH) def verify(self, request, responses, test_case): test_case.assertEqual(test_constants.STREAM_LENGTH, len(responses)) base_price = _price(request.symbol) for index, response in enumerate(responses): test_case.assertEqual(base_price + index, response.price) class GetHighestTradePrice(_service.StreamUnaryTestMethodImplementation): """GetHighestTradePrice for use in tests.""" def group(self): return _STOCK_GROUP_NAME def name(self): return 'GetHighestTradePrice' def cardinality(self): return cardinality.Cardinality.STREAM_UNARY def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, response_callback, context, control): return _get_highest_trade_price( response_callback, control, context.is_active) class GetHighestTradePriceMessages(_service.StreamUnaryTestMessages): def requests(self): return [ stock_pb2.StockRequest(symbol=_SYMBOL_FORMAT % index) for index in range(test_constants.STREAM_LENGTH)] def verify(self, requests, response, test_case): price = None symbol = None for stock_request in requests: current_symbol = stock_request.symbol current_price = _price(current_symbol) if price is None or price < current_price: price = current_price symbol = current_symbol test_case.assertEqual(price, response.price) test_case.assertEqual(symbol, response.symbol) class StockTestService(_service.TestService): """A corpus of test data with one method of each RPC cardinality.""" def unary_unary_scenarios(self): return { (_STOCK_GROUP_NAME, 'GetLastTradePrice'): ( GetLastTradePrice(), [GetLastTradePriceMessages()]), } def unary_stream_scenarios(self): return { (_STOCK_GROUP_NAME, 'WatchFutureTrades'): ( WatchFutureTrades(), [WatchFutureTradesMessages()]), } def stream_unary_scenarios(self): return { (_STOCK_GROUP_NAME, 'GetHighestTradePrice'): ( GetHighestTradePrice(), [GetHighestTradePriceMessages()]) } def stream_stream_scenarios(self): return { (_STOCK_GROUP_NAME, 'GetLastTradePriceMultiple'): ( GetLastTradePriceMultiple(), [GetLastTradePriceMultipleMessages()]), } STOCK_TEST_SERVICE = StockTestService() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py0000644000175000017500000000277212600663151030502 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py0000644000175000017500000001625412600663151032125 0ustar apollockapollock# 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. """Interfaces used in tests of implementations of the Face layer.""" import abc from grpc.framework.common import cardinality # pylint: disable=unused-import from grpc.framework.interfaces.face import face # pylint: disable=unused-import class Method(object): """Specifies a method to be used in tests.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def group(self): """Identify the group of the method. Returns: The group of the method. """ raise NotImplementedError() @abc.abstractmethod def name(self): """Identify the name of the method. Returns: The name of the method. """ raise NotImplementedError() @abc.abstractmethod def cardinality(self): """Identify the cardinality of the method. Returns: A cardinality.Cardinality value describing the streaming semantics of the method. """ raise NotImplementedError() @abc.abstractmethod def request_class(self): """Identify the class used for the method's request objects. Returns: The class object of the class to which the method's request objects belong. """ raise NotImplementedError() @abc.abstractmethod def response_class(self): """Identify the class used for the method's response objects. Returns: The class object of the class to which the method's response objects belong. """ raise NotImplementedError() @abc.abstractmethod def serialize_request(self, request): """Serialize the given request object. Args: request: A request object appropriate for this method. """ raise NotImplementedError() @abc.abstractmethod def deserialize_request(self, serialized_request): """Synthesize a request object from a given bytestring. Args: serialized_request: A bytestring deserializable into a request object appropriate for this method. """ raise NotImplementedError() @abc.abstractmethod def serialize_response(self, response): """Serialize the given response object. Args: response: A response object appropriate for this method. """ raise NotImplementedError() @abc.abstractmethod def deserialize_response(self, serialized_response): """Synthesize a response object from a given bytestring. Args: serialized_response: A bytestring deserializable into a response object appropriate for this method. """ raise NotImplementedError() class Implementation(object): """Specifies an implementation of the Face layer.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def instantiate( self, methods, method_implementations, multi_method_implementation): """Instantiates the Face layer implementation to be used in a test. Args: methods: A sequence of Method objects describing the methods available to be called during the test. method_implementations: A dictionary from group-name pair to face.MethodImplementation object specifying implementation of a method. multi_method_implementation: A face.MultiMethodImplementation or None. Returns: A sequence of length three the first element of which is a face.GenericStub, the second element of which is dictionary from groups to face.DynamicStubs affording invocation of the group's methods, and the third element of which is an arbitrary memo object to be kept and passed to destantiate at the conclusion of the test. The returned stubs must be backed by the provided implementations. """ raise NotImplementedError() @abc.abstractmethod def destantiate(self, memo): """Destroys the Face layer implementation under test. Args: memo: The object from the third position of the return value of a call to instantiate. """ raise NotImplementedError() @abc.abstractmethod def invocation_metadata(self): """Provides the metadata to be used when invoking a test RPC. Returns: An object to use as the supplied-at-invocation-time metadata in a test RPC. """ raise NotImplementedError() @abc.abstractmethod def initial_metadata(self): """Provides the metadata for use as a test RPC's first servicer metadata. Returns: An object to use as the from-the-servicer-before-responses metadata in a test RPC. """ raise NotImplementedError() @abc.abstractmethod def terminal_metadata(self): """Provides the metadata for use as a test RPC's second servicer metadata. Returns: An object to use as the from-the-servicer-after-all-responses metadata in a test RPC. """ raise NotImplementedError() @abc.abstractmethod def code(self): """Provides the value for use as a test RPC's code. Returns: An object to use as the from-the-servicer code in a test RPC. """ raise NotImplementedError() @abc.abstractmethod def details(self): """Provides the value for use as a test RPC's details. Returns: An object to use as the from-the-servicer details in a test RPC. """ raise NotImplementedError() @abc.abstractmethod def metadata_transmitted(self, original_metadata, transmitted_metadata): """Identifies whether or not metadata was properly transmitted. Args: original_metadata: A metadata value passed to the Face interface implementation under test. transmitted_metadata: The same metadata value after having been transmitted via an RPC performed by the Face interface implementation under test. Returns: Whether or not the metadata was properly transmitted by the Face interface implementation under test. """ raise NotImplementedError() ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchrono0000644000175000017500000004365212600663151034463 0ustar apollockapollock# 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. """Test code for the Face layer of RPC Framework.""" import abc import contextlib import threading import unittest # test_interfaces is referenced from specification in this module. from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import class _PauseableIterator(object): def __init__(self, upstream): self._upstream = upstream self._condition = threading.Condition() self._paused = False @contextlib.contextmanager def pause(self): with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() def __iter__(self): return self def next(self): with self._condition: while self._paused: self._condition.wait() return next(self._upstream) class _Callback(object): def __init__(self): self._condition = threading.Condition() self._called = False self._passed_future = None self._passed_other_stuff = None def __call__(self, *args, **kwargs): with self._condition: self._called = True if args: self._passed_future = args[0] if 1 < len(args) or kwargs: self._passed_other_stuff = tuple(args[1:]), dict(kwargs) self._condition.notify_all() def future(self): with self._condition: while True: if self._passed_other_stuff is not None: raise ValueError( 'Test callback passed unexpected values: %s', self._passed_other_stuff) elif self._called: return self._passed_future else: self._condition.wait() class TestCase(test_coverage.Coverage, unittest.TestCase): """A test of the Face layer of RPC Framework. Concrete subclasses must have an "implementation" attribute of type test_interfaces.Implementation and an "invoker_constructor" attribute of type _invocation.InvokerConstructor. """ __metaclass__ = abc.ABCMeta NAME = 'FutureInvocationAsynchronousEventServiceTest' def setUp(self): """See unittest.TestCase.setUp for full specification. Overriding implementations must call this implementation. """ self._control = test_control.PauseFailControl() self._digest_pool = logging_pool.pool(test_constants.POOL_SIZE) self._digest = _digest.digest( _stock_service.STOCK_TEST_SERVICE, self._control, self._digest_pool) generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate( self._digest.methods, self._digest.event_method_implementations, None) self._invoker = self.invoker_constructor.construct_invoker( generic_stub, dynamic_stubs, self._digest.methods) def tearDown(self): """See unittest.TestCase.tearDown for full specification. Overriding implementations must call this implementation. """ self._invoker = None self.implementation.destantiate(self._memo) self._digest_pool.shutdown(wait=True) def testSuccessfulUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() response_future = self._invoker.future(group, method)( request, test_constants.LONG_TIMEOUT) response_future.add_done_callback(callback) response = response_future.result() test_messages.verify(request, response, self) self.assertIs(callback.future(), response_future) def testSuccessfulUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response_iterator = self._invoker.future(group, method)( request, test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(request, responses, self) def testSuccessfulStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) callback = _Callback() # Use of a paused iterator of requests allows us to test that control is # returned to calling code before the iterator yields any requests. with request_iterator.pause(): response_future = self._invoker.future(group, method)( request_iterator, test_constants.LONG_TIMEOUT) response_future.add_done_callback(callback) future_passed_to_callback = callback.future() response = future_passed_to_callback.result() test_messages.verify(requests, response, self) self.assertIs(future_passed_to_callback, response_future) def testSuccessfulStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) # Use of a paused iterator of requests allows us to test that control is # returned to calling code before the iterator yields any requests. with request_iterator.pause(): response_iterator = self._invoker.future(group, method)( request_iterator, test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(requests, responses, self) def testSequentialInvocations(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() first_response_future = self._invoker.future(group, method)( first_request, test_constants.LONG_TIMEOUT) first_response = first_response_future.result() test_messages.verify(first_request, first_response, self) second_response_future = self._invoker.future(group, method)( second_request, test_constants.LONG_TIMEOUT) second_response = second_response_future.result() test_messages.verify(second_request, second_response, self) def testParallelInvocations(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() first_response_future = self._invoker.future(group, method)( first_request, test_constants.LONG_TIMEOUT) second_response_future = self._invoker.future(group, method)( second_request, test_constants.LONG_TIMEOUT) first_response = first_response_future.result() second_response = second_response_future.result() test_messages.verify(first_request, first_response, self) test_messages.verify(second_request, second_response, self) @unittest.skip('TODO(nathaniel): implement.') def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() def testCancelledUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() with self._control.pause(): response_future = self._invoker.future(group, method)( request, test_constants.LONG_TIMEOUT) response_future.add_done_callback(callback) cancel_method_return_value = response_future.cancel() self.assertIs(callback.future(), response_future) self.assertFalse(cancel_method_return_value) self.assertTrue(response_future.cancelled()) def testCancelledUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self._control.pause(): response_iterator = self._invoker.future(group, method)( request, test_constants.LONG_TIMEOUT) response_iterator.cancel() with self.assertRaises(face.CancellationError): next(response_iterator) def testCancelledStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = _Callback() with self._control.pause(): response_future = self._invoker.future(group, method)( iter(requests), test_constants.LONG_TIMEOUT) response_future.add_done_callback(callback) cancel_method_return_value = response_future.cancel() self.assertIs(callback.future(), response_future) self.assertFalse(cancel_method_return_value) self.assertTrue(response_future.cancelled()) def testCancelledStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self._control.pause(): response_iterator = self._invoker.future(group, method)( iter(requests), test_constants.LONG_TIMEOUT) response_iterator.cancel() with self.assertRaises(face.CancellationError): next(response_iterator) def testExpiredUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() with self._control.pause(): response_future = self._invoker.future( group, method)(request, _3069_test_constant.REALLY_SHORT_TIMEOUT) response_future.add_done_callback(callback) self.assertIs(callback.future(), response_future) self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): response_future.result() def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self._control.pause(): response_iterator = self._invoker.future(group, method)( request, _3069_test_constant.REALLY_SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = _Callback() with self._control.pause(): response_future = self._invoker.future(group, method)( iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) response_future.add_done_callback(callback) self.assertIs(callback.future(), response_future) self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): response_future.result() def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self._control.pause(): response_iterator = self._invoker.future(group, method)( iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = _Callback() with self._control.fail(): response_future = self._invoker.future(group, method)( request, _3069_test_constant.REALLY_SHORT_TIMEOUT) response_future.add_done_callback(callback) self.assertIs(callback.future(), response_future) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is # indistinguishable from simply not having called its # response_callback before the expiration of the RPC. self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): response_future.result() def testFailedUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is indistinguishable # from simply not having called its response_consumer before the # expiration of the RPC. with self._control.fail(), self.assertRaises(face.ExpirationError): response_iterator = self._invoker.future(group, method)( request, _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = _Callback() with self._control.fail(): response_future = self._invoker.future(group, method)( iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) response_future.add_done_callback(callback) self.assertIs(callback.future(), response_future) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is # indistinguishable from simply not having called its # response_callback before the expiration of the RPC. self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): response_future.result() def testFailedStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is indistinguishable # from simply not having called its response_consumer before the # expiration of the RPC. with self._control.fail(), self.assertRaises(face.ExpirationError): response_iterator = self._invoker.future(group, method)( iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py0000644000175000017500000000346712600663151032455 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A test constant working around issue 3069.""" # test_constants is referenced from specification in this module. from grpc_test.framework.common import test_constants # pylint: disable=unused-import # TODO(issue 3069): Replace uses of this constant with # test_constants.SHORT_TIMEOUT. REALLY_SHORT_TIMEOUT = 0.1 ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_s0000644000175000017500000002504212600663151034347 0ustar apollockapollock# 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. """Test code for the Face layer of RPC Framework.""" import abc import unittest # test_interfaces is referenced from specification in this module. from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import class TestCase(test_coverage.Coverage, unittest.TestCase): """A test of the Face layer of RPC Framework. Concrete subclasses must have an "implementation" attribute of type test_interfaces.Implementation and an "invoker_constructor" attribute of type _invocation.InvokerConstructor. """ __metaclass__ = abc.ABCMeta NAME = 'BlockingInvocationInlineServiceTest' def setUp(self): """See unittest.TestCase.setUp for full specification. Overriding implementations must call this implementation. """ self._control = test_control.PauseFailControl() self._digest = _digest.digest( _stock_service.STOCK_TEST_SERVICE, self._control, None) generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate( self._digest.methods, self._digest.inline_method_implementations, None) self._invoker = self.invoker_constructor.construct_invoker( generic_stub, dynamic_stubs, self._digest.methods) def tearDown(self): """See unittest.TestCase.tearDown for full specification. Overriding implementations must call this implementation. """ self._invoker = None self.implementation.destantiate(self._memo) def testSuccessfulUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response, call = self._invoker.blocking(group, method)( request, test_constants.LONG_TIMEOUT, with_call=True) test_messages.verify(request, response, self) def testSuccessfulUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response_iterator = self._invoker.blocking(group, method)( request, test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(request, responses, self) def testSuccessfulStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() response, call = self._invoker.blocking(group, method)( iter(requests), test_constants.LONG_TIMEOUT, with_call=True) test_messages.verify(requests, response, self) def testSuccessfulStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() response_iterator = self._invoker.blocking(group, method)( iter(requests), test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(requests, responses, self) def testSequentialInvocations(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() first_response = self._invoker.blocking(group, method)( first_request, test_constants.LONG_TIMEOUT) test_messages.verify(first_request, first_response, self) second_response = self._invoker.blocking(group, method)( second_request, test_constants.LONG_TIMEOUT) test_messages.verify(second_request, second_response, self) @unittest.skip('Parallel invocations impossible with blocking control flow!') def testParallelInvocations(self): raise NotImplementedError() @unittest.skip('Parallel invocations impossible with blocking control flow!') def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() @unittest.skip('Cancellation impossible with blocking control flow!') def testCancelledUnaryRequestUnaryResponse(self): raise NotImplementedError() @unittest.skip('Cancellation impossible with blocking control flow!') def testCancelledUnaryRequestStreamResponse(self): raise NotImplementedError() @unittest.skip('Cancellation impossible with blocking control flow!') def testCancelledStreamRequestUnaryResponse(self): raise NotImplementedError() @unittest.skip('Cancellation impossible with blocking control flow!') def testCancelledStreamRequestStreamResponse(self): raise NotImplementedError() def testExpiredUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self._control.pause(), self.assertRaises( face.ExpirationError): self._invoker.blocking(group, method)( request, _3069_test_constant.REALLY_SHORT_TIMEOUT) def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self._control.pause(), self.assertRaises( face.ExpirationError): response_iterator = self._invoker.blocking(group, method)( request, _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self._control.pause(), self.assertRaises( face.ExpirationError): self._invoker.blocking(group, method)( iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self._control.pause(), self.assertRaises( face.ExpirationError): response_iterator = self._invoker.blocking(group, method)( iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self._control.fail(), self.assertRaises(face.RemoteError): self._invoker.blocking(group, method)( request, test_constants.LONG_TIMEOUT) def testFailedUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self._control.fail(), self.assertRaises(face.RemoteError): response_iterator = self._invoker.blocking(group, method)( request, test_constants.LONG_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self._control.fail(), self.assertRaises(face.RemoteError): self._invoker.blocking(group, method)( iter(requests), test_constants.LONG_TIMEOUT) def testFailedStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self._control.fail(), self.assertRaises(face.RemoteError): response_iterator = self._invoker.blocking(group, method)( iter(requests), test_constants.LONG_TIMEOUT) list(response_iterator) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py0000644000175000017500000000655612600663151030712 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A utility useful in tests of asynchronous, event-driven interfaces.""" import threading from grpc.framework.interfaces.face import face class Receiver(face.ResponseReceiver): """A utility object useful in tests of asynchronous code.""" def __init__(self): self._condition = threading.Condition() self._initial_metadata = None self._responses = [] self._terminal_metadata = None self._code = None self._details = None self._completed = False self._abortion = None def abort(self, abortion): with self._condition: self._abortion = abortion self._condition.notify_all() def initial_metadata(self, initial_metadata): with self._condition: self._initial_metadata = initial_metadata def response(self, response): with self._condition: self._responses.append(response) def complete(self, terminal_metadata, code, details): with self._condition: self._terminal_metadata = terminal_metadata self._code = code self._details = details self._completed = True self._condition.notify_all() def block_until_terminated(self): with self._condition: while self._abortion is None and not self._completed: self._condition.wait() def unary_response(self): with self._condition: if self._abortion is not None: raise AssertionError('Aborted with abortion "%s"!' % self._abortion) elif len(self._responses) != 1: raise AssertionError( '%d responses received, not exactly one!', len(self._responses)) else: return self._responses[0] def stream_responses(self): with self._condition: if self._abortion is None: return list(self._responses) else: raise AssertionError('Aborted with abortion "%s"!' % self._abortion) def abortion(self): with self._condition: return self._abortion grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py0000644000175000017500000000615012600663151031072 0ustar apollockapollock# 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. """Tools for creating tests of implementations of the Face layer.""" # unittest is referenced from specification in this module. import unittest # pylint: disable=unused-import # test_interfaces is referenced from specification in this module. from grpc_test.framework.interfaces.face import _blocking_invocation_inline_service from grpc_test.framework.interfaces.face import _event_invocation_synchronous_event_service from grpc_test.framework.interfaces.face import _future_invocation_asynchronous_event_service from grpc_test.framework.interfaces.face import _invocation from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import _TEST_CASE_SUPERCLASSES = ( _blocking_invocation_inline_service.TestCase, _event_invocation_synchronous_event_service.TestCase, _future_invocation_asynchronous_event_service.TestCase, ) def test_cases(implementation): """Creates unittest.TestCase classes for a given Face layer implementation. Args: implementation: A test_interfaces.Implementation specifying creation and destruction of a given Face layer implementation. Returns: A sequence of subclasses of unittest.TestCase defining tests of the specified Face layer implementation. """ test_case_classes = [] for invoker_constructor in _invocation.invoker_constructors(): for super_class in _TEST_CASE_SUPERCLASSES: test_case_classes.append( type(invoker_constructor.name() + super_class.NAME, (super_class,), {'implementation': implementation, 'invoker_constructor': invoker_constructor})) return test_case_classes ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous0000644000175000017500000003711012600663151034471 0ustar apollockapollock# 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. """Test code for the Face layer of RPC Framework.""" import abc import unittest # test_interfaces is referenced from specification in this module. from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _receiver from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import class TestCase(test_coverage.Coverage, unittest.TestCase): """A test of the Face layer of RPC Framework. Concrete subclasses must have an "implementation" attribute of type test_interfaces.Implementation and an "invoker_constructor" attribute of type _invocation.InvokerConstructor. """ __metaclass__ = abc.ABCMeta NAME = 'EventInvocationSynchronousEventServiceTest' def setUp(self): """See unittest.TestCase.setUp for full specification. Overriding implementations must call this implementation. """ self._control = test_control.PauseFailControl() self._digest = _digest.digest( _stock_service.STOCK_TEST_SERVICE, self._control, None) generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate( self._digest.methods, self._digest.event_method_implementations, None) self._invoker = self.invoker_constructor.construct_invoker( generic_stub, dynamic_stubs, self._digest.methods) def tearDown(self): """See unittest.TestCase.tearDown for full specification. Overriding implementations must call this implementation. """ self._invoker = None self.implementation.destantiate(self._memo) def testSuccessfulUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() self._invoker.event(group, method)( request, receiver, receiver.abort, test_constants.LONG_TIMEOUT) receiver.block_until_terminated() response = receiver.unary_response() test_messages.verify(request, response, self) def testSuccessfulUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() self._invoker.event(group, method)( request, receiver, receiver.abort, test_constants.LONG_TIMEOUT) receiver.block_until_terminated() responses = receiver.stream_responses() test_messages.verify(request, responses, self) def testSuccessfulStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, test_constants.LONG_TIMEOUT) for request in requests: call_consumer.consume(request) call_consumer.terminate() receiver.block_until_terminated() response = receiver.unary_response() test_messages.verify(requests, response, self) def testSuccessfulStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, test_constants.LONG_TIMEOUT) for request in requests: call_consumer.consume(request) call_consumer.terminate() receiver.block_until_terminated() responses = receiver.stream_responses() test_messages.verify(requests, responses, self) def testSequentialInvocations(self): # pylint: disable=cell-var-from-loop for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() second_receiver = _receiver.Receiver() def make_second_invocation(): self._invoker.event(group, method)( second_request, second_receiver, second_receiver.abort, test_constants.LONG_TIMEOUT) class FirstReceiver(_receiver.Receiver): def complete(self, terminal_metadata, code, details): super(FirstReceiver, self).complete( terminal_metadata, code, details) make_second_invocation() first_receiver = FirstReceiver() self._invoker.event(group, method)( first_request, first_receiver, first_receiver.abort, test_constants.LONG_TIMEOUT) second_receiver.block_until_terminated() first_response = first_receiver.unary_response() second_response = second_receiver.unary_response() test_messages.verify(first_request, first_response, self) test_messages.verify(second_request, second_response, self) def testParallelInvocations(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() first_receiver = _receiver.Receiver() second_request = test_messages.request() second_receiver = _receiver.Receiver() self._invoker.event(group, method)( first_request, first_receiver, first_receiver.abort, test_constants.LONG_TIMEOUT) self._invoker.event(group, method)( second_request, second_receiver, second_receiver.abort, test_constants.LONG_TIMEOUT) first_receiver.block_until_terminated() second_receiver.block_until_terminated() first_response = first_receiver.unary_response() second_response = second_receiver.unary_response() test_messages.verify(first_request, first_response, self) test_messages.verify(second_request, second_response, self) @unittest.skip('TODO(nathaniel): implement.') def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() def testCancelledUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() with self._control.pause(): call = self._invoker.event(group, method)( request, receiver, receiver.abort, test_constants.LONG_TIMEOUT) call.cancel() receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind) def testCancelledUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() call = self._invoker.event(group, method)( request, receiver, receiver.abort, test_constants.LONG_TIMEOUT) call.cancel() receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind) def testCancelledStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, test_constants.LONG_TIMEOUT) for request in requests: call_consumer.consume(request) call_consumer.cancel() receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind) def testCancelledStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for unused_test_messages in test_messages_sequence: receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, test_constants.LONG_TIMEOUT) call_consumer.cancel() receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind) def testExpiredUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() with self._control.pause(): self._invoker.event(group, method)( request, receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() with self._control.pause(): self._invoker.event(group, method)( request, receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) def testExpiredStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for unused_test_messages in test_messages_sequence: receiver = _receiver.Receiver() self._invoker.event(group, method)( receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) for request in requests: call_consumer.consume(request) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) def testFailedUnaryRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() with self._control.fail(): self._invoker.event(group, method)( request, receiver, receiver.abort, test_constants.LONG_TIMEOUT) receiver.block_until_terminated() self.assertIs( face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind) def testFailedUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() receiver = _receiver.Receiver() with self._control.fail(): self._invoker.event(group, method)( request, receiver, receiver.abort, test_constants.LONG_TIMEOUT) receiver.block_until_terminated() self.assertIs( face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind) def testFailedStreamRequestUnaryResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() receiver = _receiver.Receiver() with self._control.fail(): call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, test_constants.LONG_TIMEOUT) for request in requests: call_consumer.consume(request) call_consumer.terminate() receiver.block_until_terminated() self.assertIs( face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind) def testFailedStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( self._digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() receiver = _receiver.Receiver() with self._control.fail(): call_consumer = self._invoker.event(group, method)( receiver, receiver.abort, test_constants.LONG_TIMEOUT) for request in requests: call_consumer.consume(request) call_consumer.terminate() receiver.block_until_terminated() self.assertIs( face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py0000644000175000017500000002643112600663151030540 0ustar apollockapollock# 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. """Private interfaces implemented by data sets used in Face-layer tests.""" import abc # face is referenced from specification in this module. from grpc.framework.interfaces.face import face # pylint: disable=unused-import from grpc_test.framework.interfaces.face import test_interfaces class UnaryUnaryTestMethodImplementation(test_interfaces.Method): """A controllable implementation of a unary-unary method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, request, response_callback, context, control): """Services an RPC that accepts one message and produces one message. Args: request: The single request message for the RPC. response_callback: A callback to be called to accept the response message of the RPC. context: An face.ServicerContext object. control: A test_control.Control to control execution of this method. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class UnaryUnaryTestMessages(object): """A type for unary-request-unary-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def request(self): """Affords a request message. Implementations of this method should return a different message with each call so that multiple test executions of the test method may be made with different inputs. Returns: A request message. """ raise NotImplementedError() @abc.abstractmethod def verify(self, request, response, test_case): """Verifies that the computed response matches the given request. Args: request: A request message. response: A response message. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the request and response do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class UnaryStreamTestMethodImplementation(test_interfaces.Method): """A controllable implementation of a unary-stream method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, request, response_consumer, context, control): """Services an RPC that takes one message and produces a stream of messages. Args: request: The single request message for the RPC. response_consumer: A stream.Consumer to be called to accept the response messages of the RPC. context: A face.ServicerContext object. control: A test_control.Control to control execution of this method. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class UnaryStreamTestMessages(object): """A type for unary-request-stream-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def request(self): """Affords a request message. Implementations of this method should return a different message with each call so that multiple test executions of the test method may be made with different inputs. Returns: A request message. """ raise NotImplementedError() @abc.abstractmethod def verify(self, request, responses, test_case): """Verifies that the computed responses match the given request. Args: request: A request message. responses: A sequence of response messages. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the request and responses do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class StreamUnaryTestMethodImplementation(test_interfaces.Method): """A controllable implementation of a stream-unary method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, response_callback, context, control): """Services an RPC that takes a stream of messages and produces one message. Args: response_callback: A callback to be called to accept the response message of the RPC. context: A face.ServicerContext object. control: A test_control.Control to control execution of this method. Returns: A stream.Consumer with which to accept the request messages of the RPC. The consumer returned from this method may or may not be invoked to completion: in the case of RPC abortion, RPC Framework will simply stop passing messages to this object. Implementations must not assume that this object will be called to completion of the request stream or even called at all. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class StreamUnaryTestMessages(object): """A type for stream-request-unary-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def requests(self): """Affords a sequence of request messages. Implementations of this method should return a different sequences with each call so that multiple test executions of the test method may be made with different inputs. Returns: A sequence of request messages. """ raise NotImplementedError() @abc.abstractmethod def verify(self, requests, response, test_case): """Verifies that the computed response matches the given requests. Args: requests: A sequence of request messages. response: A response message. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the requests and response do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class StreamStreamTestMethodImplementation(test_interfaces.Method): """A controllable implementation of a stream-stream method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, response_consumer, context, control): """Services an RPC that accepts and produces streams of messages. Args: response_consumer: A stream.Consumer to be called to accept the response messages of the RPC. context: A face.ServicerContext object. control: A test_control.Control to control execution of this method. Returns: A stream.Consumer with which to accept the request messages of the RPC. The consumer returned from this method may or may not be invoked to completion: in the case of RPC abortion, RPC Framework will simply stop passing messages to this object. Implementations must not assume that this object will be called to completion of the request stream or even called at all. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class StreamStreamTestMessages(object): """A type for stream-request-stream-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def requests(self): """Affords a sequence of request messages. Implementations of this method should return a different sequences with each call so that multiple test executions of the test method may be made with different inputs. Returns: A sequence of request messages. """ raise NotImplementedError() @abc.abstractmethod def verify(self, requests, responses, test_case): """Verifies that the computed response matches the given requests. Args: requests: A sequence of request messages. responses: A sequence of response messages. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the requests and responses do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class TestService(object): """A specification of implemented methods to use in tests.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def unary_unary_scenarios(self): """Affords unary-request-unary-response test methods and their messages. Returns: A dict from method group-name pair to implementation/messages pair. The first element of the pair is a UnaryUnaryTestMethodImplementation object and the second element is a sequence of UnaryUnaryTestMethodMessages objects. """ raise NotImplementedError() @abc.abstractmethod def unary_stream_scenarios(self): """Affords unary-request-stream-response test methods and their messages. Returns: A dict from method group-name pair to implementation/messages pair. The first element of the pair is a UnaryStreamTestMethodImplementation object and the second element is a sequence of UnaryStreamTestMethodMessages objects. """ raise NotImplementedError() @abc.abstractmethod def stream_unary_scenarios(self): """Affords stream-request-unary-response test methods and their messages. Returns: A dict from method group-name pair to implementation/messages pair. The first element of the pair is a StreamUnaryTestMethodImplementation object and the second element is a sequence of StreamUnaryTestMethodMessages objects. """ raise NotImplementedError() @abc.abstractmethod def stream_stream_scenarios(self): """Affords stream-request-stream-response test methods and their messages. Returns: A dict from method group-name pair to implementation/messages pair. The first element of the pair is a StreamStreamTestMethodImplementation object and the second element is a sequence of StreamStreamTestMethodMessages objects. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py0000644000175000017500000000277212600663151027604 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/0000755000175000017500000000000012600663151026375 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py0000644000175000017500000005221212600663151030570 0ustar apollockapollock# 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. """Part of the tests of the base interface of RPC Framework.""" import abc import collections import enum import random # pylint: disable=unused-import import threading import time from grpc.framework.interfaces.base import base from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.base import _sequence from grpc_test.framework.interfaces.base import _state from grpc_test.framework.interfaces.base import test_interfaces # pylint: disable=unused-import _GROUP = 'base test cases test group' _METHOD = 'base test cases test method' _PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE = test_constants.PAYLOAD_SIZE / 20 _MINIMUM_PAYLOAD_SIZE = test_constants.PAYLOAD_SIZE / 600 def _create_payload(randomness): length = randomness.randint( _MINIMUM_PAYLOAD_SIZE, test_constants.PAYLOAD_SIZE) random_section_length = randomness.randint( 0, min(_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE, length)) random_section = bytes( bytearray( randomness.getrandbits(8) for _ in range(random_section_length))) sevens_section = '\x07' * (length - random_section_length) return b''.join(randomness.sample((random_section, sevens_section), 2)) def _anything_in_flight(state): return ( state.invocation_initial_metadata_in_flight is not None or state.invocation_payloads_in_flight or state.invocation_completion_in_flight is not None or state.service_initial_metadata_in_flight is not None or state.service_payloads_in_flight or state.service_completion_in_flight is not None or 0 < state.invocation_allowance_in_flight or 0 < state.service_allowance_in_flight ) def _verify_service_advance_and_update_state( initial_metadata, payload, completion, allowance, state, implementation): if initial_metadata is not None: if state.invocation_initial_metadata_received: return 'Later invocation initial metadata received: %s' % ( initial_metadata,) if state.invocation_payloads_received: return 'Invocation initial metadata received after payloads: %s' % ( state.invocation_payloads_received) if state.invocation_completion_received: return 'Invocation initial metadata received after invocation completion!' if not implementation.metadata_transmitted( state.invocation_initial_metadata_in_flight, initial_metadata): return 'Invocation initial metadata maltransmitted: %s, %s' % ( state.invocation_initial_metadata_in_flight, initial_metadata) else: state.invocation_initial_metadata_in_flight = None state.invocation_initial_metadata_received = True if payload is not None: if state.invocation_completion_received: return 'Invocation payload received after invocation completion!' elif not state.invocation_payloads_in_flight: return 'Invocation payload "%s" received but not in flight!' % (payload,) elif state.invocation_payloads_in_flight[0] != payload: return 'Invocation payload mismatch: %s, %s' % ( state.invocation_payloads_in_flight[0], payload) elif state.service_side_invocation_allowance < 1: return 'Disallowed invocation payload!' else: state.invocation_payloads_in_flight.pop(0) state.invocation_payloads_received += 1 state.service_side_invocation_allowance -= 1 if completion is not None: if state.invocation_completion_received: return 'Later invocation completion received: %s' % (completion,) elif not implementation.completion_transmitted( state.invocation_completion_in_flight, completion): return 'Invocation completion maltransmitted: %s, %s' % ( state.invocation_completion_in_flight, completion) else: state.invocation_completion_in_flight = None state.invocation_completion_received = True if allowance is not None: if allowance <= 0: return 'Illegal allowance value: %s' % (allowance,) else: state.service_allowance_in_flight -= allowance state.service_side_service_allowance += allowance def _verify_invocation_advance_and_update_state( initial_metadata, payload, completion, allowance, state, implementation): if initial_metadata is not None: if state.service_initial_metadata_received: return 'Later service initial metadata received: %s' % (initial_metadata,) if state.service_payloads_received: return 'Service initial metadata received after service payloads: %s' % ( state.service_payloads_received) if state.service_completion_received: return 'Service initial metadata received after service completion!' if not implementation.metadata_transmitted( state.service_initial_metadata_in_flight, initial_metadata): return 'Service initial metadata maltransmitted: %s, %s' % ( state.service_initial_metadata_in_flight, initial_metadata) else: state.service_initial_metadata_in_flight = None state.service_initial_metadata_received = True if payload is not None: if state.service_completion_received: return 'Service payload received after service completion!' elif not state.service_payloads_in_flight: return 'Service payload "%s" received but not in flight!' % (payload,) elif state.service_payloads_in_flight[0] != payload: return 'Service payload mismatch: %s, %s' % ( state.invocation_payloads_in_flight[0], payload) elif state.invocation_side_service_allowance < 1: return 'Disallowed service payload!' else: state.service_payloads_in_flight.pop(0) state.service_payloads_received += 1 state.invocation_side_service_allowance -= 1 if completion is not None: if state.service_completion_received: return 'Later service completion received: %s' % (completion,) elif not implementation.completion_transmitted( state.service_completion_in_flight, completion): return 'Service completion maltransmitted: %s, %s' % ( state.service_completion_in_flight, completion) else: state.service_completion_in_flight = None state.service_completion_received = True if allowance is not None: if allowance <= 0: return 'Illegal allowance value: %s' % (allowance,) else: state.invocation_allowance_in_flight -= allowance state.invocation_side_service_allowance += allowance class Invocation( collections.namedtuple( 'Invocation', ('group', 'method', 'subscription_kind', 'timeout', 'initial_metadata', 'payload', 'completion',))): """A description of operation invocation. Attributes: group: The group identifier for the operation. method: The method identifier for the operation. subscription_kind: A base.Subscription.Kind value describing the kind of subscription to use for the operation. timeout: A duration in seconds to pass as the timeout value for the operation. initial_metadata: An object to pass as the initial metadata for the operation or None. payload: An object to pass as a payload value for the operation or None. completion: An object to pass as a completion value for the operation or None. """ class OnAdvance( collections.namedtuple( 'OnAdvance', ('kind', 'initial_metadata', 'payload', 'completion', 'allowance'))): """Describes action to be taken in a test in response to an advance call. Attributes: kind: A Kind value describing the overall kind of response. initial_metadata: An initial metadata value to pass to a call of the advance method of the operator under test. Only valid if kind is Kind.ADVANCE and may be None. payload: A payload value to pass to a call of the advance method of the operator under test. Only valid if kind is Kind.ADVANCE and may be None. completion: A base.Completion value to pass to a call of the advance method of the operator under test. Only valid if kind is Kind.ADVANCE and may be None. allowance: An allowance value to pass to a call of the advance method of the operator under test. Only valid if kind is Kind.ADVANCE and may be None. """ @enum.unique class Kind(enum.Enum): ADVANCE = 'advance' DEFECT = 'defect' IDLE = 'idle' _DEFECT_ON_ADVANCE = OnAdvance(OnAdvance.Kind.DEFECT, None, None, None, None) _IDLE_ON_ADVANCE = OnAdvance(OnAdvance.Kind.IDLE, None, None, None, None) class Instruction( collections.namedtuple( 'Instruction', ('kind', 'advance_args', 'advance_kwargs', 'conclude_success', 'conclude_message', 'conclude_invocation_outcome_kind', 'conclude_service_outcome_kind',))): """""" @enum.unique class Kind(enum.Enum): ADVANCE = 'ADVANCE' CANCEL = 'CANCEL' CONCLUDE = 'CONCLUDE' class Controller(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def failed(self, message): """""" raise NotImplementedError() @abc.abstractmethod def serialize_request(self, request): """""" raise NotImplementedError() @abc.abstractmethod def deserialize_request(self, serialized_request): """""" raise NotImplementedError() @abc.abstractmethod def serialize_response(self, response): """""" raise NotImplementedError() @abc.abstractmethod def deserialize_response(self, serialized_response): """""" raise NotImplementedError() @abc.abstractmethod def invocation(self): """""" raise NotImplementedError() @abc.abstractmethod def poll(self): """""" raise NotImplementedError() @abc.abstractmethod def on_service_advance( self, initial_metadata, payload, completion, allowance): """""" raise NotImplementedError() @abc.abstractmethod def on_invocation_advance( self, initial_metadata, payload, completion, allowance): """""" raise NotImplementedError() @abc.abstractmethod def service_on_termination(self, outcome): """""" raise NotImplementedError() @abc.abstractmethod def invocation_on_termination(self, outcome): """""" raise NotImplementedError() class ControllerCreator(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def name(self): """""" raise NotImplementedError() @abc.abstractmethod def controller(self, implementation, randomness): """""" raise NotImplementedError() class _Remainder( collections.namedtuple( '_Remainder', ('invocation_payloads', 'service_payloads', 'invocation_completion', 'service_completion',))): """Describes work remaining to be done in a portion of a test. Attributes: invocation_payloads: The number of payloads to be sent from the invocation side of the operation to the service side of the operation. service_payloads: The number of payloads to be sent from the service side of the operation to the invocation side of the operation. invocation_completion: Whether or not completion from the invocation side of the operation should be indicated and has yet to be indicated. service_completion: Whether or not completion from the service side of the operation should be indicated and has yet to be indicated. """ class _SequenceController(Controller): def __init__(self, sequence, implementation, randomness): """Constructor. Args: sequence: A _sequence.Sequence describing the steps to be taken in the test at a relatively high level. implementation: A test_interfaces.Implementation encapsulating the base interface implementation that is the system under test. randomness: A random.Random instance for use in the test. """ self._condition = threading.Condition() self._sequence = sequence self._implementation = implementation self._randomness = randomness self._until = None self._remaining_elements = None self._poll_next = None self._message = None self._state = _state.OperationState() self._todo = None # called with self._condition def _failed(self, message): self._message = message self._condition.notify_all() def _passed(self, invocation_outcome, service_outcome): self._poll_next = Instruction( Instruction.Kind.CONCLUDE, None, None, True, None, invocation_outcome, service_outcome) self._condition.notify_all() def failed(self, message): with self._condition: self._failed(message) def serialize_request(self, request): return request + request def deserialize_request(self, serialized_request): return serialized_request[:len(serialized_request) / 2] def serialize_response(self, response): return response * 3 def deserialize_response(self, serialized_response): return serialized_response[2 * len(serialized_response) / 3:] def invocation(self): with self._condition: self._until = time.time() + self._sequence.maximum_duration self._remaining_elements = list(self._sequence.elements) if self._sequence.invocation.initial_metadata: initial_metadata = self._implementation.invocation_initial_metadata() self._state.invocation_initial_metadata_in_flight = initial_metadata else: initial_metadata = None if self._sequence.invocation.payload: payload = _create_payload(self._randomness) self._state.invocation_payloads_in_flight.append(payload) else: payload = None if self._sequence.invocation.complete: completion = self._implementation.invocation_completion() self._state.invocation_completion_in_flight = completion else: completion = None return Invocation( _GROUP, _METHOD, base.Subscription.Kind.FULL, self._sequence.invocation.timeout, initial_metadata, payload, completion) def poll(self): with self._condition: while True: if self._message is not None: return Instruction( Instruction.Kind.CONCLUDE, None, None, False, self._message, None, None) elif self._poll_next: poll_next = self._poll_next self._poll_next = None return poll_next elif self._until < time.time(): return Instruction( Instruction.Kind.CONCLUDE, None, None, False, 'overran allotted time!', None, None) else: self._condition.wait(timeout=self._until-time.time()) def on_service_advance( self, initial_metadata, payload, completion, allowance): with self._condition: message = _verify_service_advance_and_update_state( initial_metadata, payload, completion, allowance, self._state, self._implementation) if message is not None: self._failed(message) if self._todo is not None: raise ValueError('TODO!!!') elif _anything_in_flight(self._state): return _IDLE_ON_ADVANCE elif self._remaining_elements: element = self._remaining_elements.pop(0) if element.kind is _sequence.Element.Kind.SERVICE_TRANSMISSION: if element.transmission.initial_metadata: initial_metadata = self._implementation.service_initial_metadata() self._state.service_initial_metadata_in_flight = initial_metadata else: initial_metadata = None if element.transmission.payload: payload = _create_payload(self._randomness) self._state.service_payloads_in_flight.append(payload) self._state.service_side_service_allowance -= 1 else: payload = None if element.transmission.complete: completion = self._implementation.service_completion() self._state.service_completion_in_flight = completion else: completion = None if (not self._state.invocation_completion_received and 0 <= self._state.service_side_invocation_allowance): allowance = 1 self._state.service_side_invocation_allowance += 1 self._state.invocation_allowance_in_flight += 1 else: allowance = None return OnAdvance( OnAdvance.Kind.ADVANCE, initial_metadata, payload, completion, allowance) else: raise ValueError('TODO!!!') else: return _IDLE_ON_ADVANCE def on_invocation_advance( self, initial_metadata, payload, completion, allowance): with self._condition: message = _verify_invocation_advance_and_update_state( initial_metadata, payload, completion, allowance, self._state, self._implementation) if message is not None: self._failed(message) if self._todo is not None: raise ValueError('TODO!!!') elif _anything_in_flight(self._state): return _IDLE_ON_ADVANCE elif self._remaining_elements: element = self._remaining_elements.pop(0) if element.kind is _sequence.Element.Kind.INVOCATION_TRANSMISSION: if element.transmission.initial_metadata: initial_metadata = self._implementation.invocation_initial_metadata() self._state.invocation_initial_metadata_in_fight = initial_metadata else: initial_metadata = None if element.transmission.payload: payload = _create_payload(self._randomness) self._state.invocation_payloads_in_flight.append(payload) self._state.invocation_side_invocation_allowance -= 1 else: payload = None if element.transmission.complete: completion = self._implementation.invocation_completion() self._state.invocation_completion_in_flight = completion else: completion = None if (not self._state.service_completion_received and 0 <= self._state.invocation_side_service_allowance): allowance = 1 self._state.invocation_side_service_allowance += 1 self._state.service_allowance_in_flight += 1 else: allowance = None return OnAdvance( OnAdvance.Kind.ADVANCE, initial_metadata, payload, completion, allowance) else: raise ValueError('TODO!!!') else: return _IDLE_ON_ADVANCE def service_on_termination(self, outcome): with self._condition: self._state.service_side_outcome = outcome if self._todo is not None or self._remaining_elements: self._failed('Premature service-side outcome %s!' % (outcome,)) elif outcome.kind is not self._sequence.outcome_kinds.service: self._failed( 'Incorrect service-side outcome kind: %s should have been %s' % ( outcome.kind, self._sequence.outcome_kinds.service)) elif self._state.invocation_side_outcome is not None: self._passed(self._state.invocation_side_outcome.kind, outcome.kind) def invocation_on_termination(self, outcome): with self._condition: self._state.invocation_side_outcome = outcome if self._todo is not None or self._remaining_elements: self._failed('Premature invocation-side outcome %s!' % (outcome,)) elif outcome.kind is not self._sequence.outcome_kinds.invocation: self._failed( 'Incorrect invocation-side outcome kind: %s should have been %s' % ( outcome.kind, self._sequence.outcome_kinds.invocation)) elif self._state.service_side_outcome is not None: self._passed(outcome.kind, self._state.service_side_outcome.kind) class _SequenceControllerCreator(ControllerCreator): def __init__(self, sequence): self._sequence = sequence def name(self): return self._sequence.name def controller(self, implementation, randomness): return _SequenceController(self._sequence, implementation, randomness) CONTROLLER_CREATORS = tuple( _SequenceControllerCreator(sequence) for sequence in _sequence.SEQUENCES) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py0000644000175000017500000001461612600663151030726 0ustar apollockapollock# 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. """Part of the tests of the base interface of RPC Framework.""" import collections import enum from grpc.framework.interfaces.base import base from grpc_test.framework.common import test_constants class Invocation( collections.namedtuple( 'Invocation', ('timeout', 'initial_metadata', 'payload', 'complete',))): """A recipe for operation invocation. Attributes: timeout: A duration in seconds to pass to the system under test as the operation's timeout value. initial_metadata: A boolean indicating whether or not to pass initial metadata when invoking the operation. payload: A boolean indicating whether or not to pass a payload when invoking the operation. complete: A boolean indicating whether or not to indicate completion of transmissions from the invoking side of the operation when invoking the operation. """ class Transmission( collections.namedtuple( 'Transmission', ('initial_metadata', 'payload', 'complete',))): """A recipe for a single transmission in an operation. Attributes: initial_metadata: A boolean indicating whether or not to pass initial metadata as part of the transmission. payload: A boolean indicating whether or not to pass a payload as part of the transmission. complete: A boolean indicating whether or not to indicate completion of transmission from the transmitting side of the operation as part of the transmission. """ class Intertransmission( collections.namedtuple('Intertransmission', ('invocation', 'service',))): """A recipe for multiple transmissions in an operation. Attributes: invocation: An integer describing the number of payloads to send from the invocation side of the operation to the service side. service: An integer describing the number of payloads to send from the service side of the operation to the invocation side. """ class Element(collections.namedtuple('Element', ('kind', 'transmission',))): """A sum type for steps to perform when testing an operation. Attributes: kind: A Kind value describing the kind of step to perform in the test. transmission: Only valid for kinds Kind.INVOCATION_TRANSMISSION and Kind.SERVICE_TRANSMISSION, a Transmission value describing the details of the transmission to be made. """ @enum.unique class Kind(enum.Enum): INVOCATION_TRANSMISSION = 'invocation transmission' SERVICE_TRANSMISSION = 'service transmission' INTERTRANSMISSION = 'intertransmission' INVOCATION_CANCEL = 'invocation cancel' SERVICE_CANCEL = 'service cancel' INVOCATION_FAILURE = 'invocation failure' SERVICE_FAILURE = 'service failure' class OutcomeKinds( collections.namedtuple('Outcome', ('invocation', 'service',))): """A description of the expected outcome of an operation test. Attributes: invocation: The base.Outcome.Kind value expected on the invocation side of the operation. service: The base.Outcome.Kind value expected on the service side of the operation. """ class Sequence( collections.namedtuple( 'Sequence', ('name', 'maximum_duration', 'invocation', 'elements', 'outcome_kinds',))): """Describes at a high level steps to perform in a test. Attributes: name: The string name of the sequence. maximum_duration: A length of time in seconds to allow for the test before declaring it to have failed. invocation: An Invocation value describing how to invoke the operation under test. elements: A sequence of Element values describing at coarse granularity actions to take during the operation under test. outcome_kinds: An OutcomeKinds value describing the expected outcome kinds of the test. """ _EASY = Sequence( 'Easy', test_constants.TIME_ALLOWANCE, Invocation(test_constants.LONG_TIMEOUT, True, True, True), ( Element( Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, True)), ), OutcomeKinds(base.Outcome.Kind.COMPLETED, base.Outcome.Kind.COMPLETED)) _PEASY = Sequence( 'Peasy', test_constants.TIME_ALLOWANCE, Invocation(test_constants.LONG_TIMEOUT, True, True, False), ( Element( Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, False)), Element( Element.Kind.INVOCATION_TRANSMISSION, Transmission(False, True, True)), Element( Element.Kind.SERVICE_TRANSMISSION, Transmission(False, True, True)), ), OutcomeKinds(base.Outcome.Kind.COMPLETED, base.Outcome.Kind.COMPLETED)) # TODO(issue 2959): Finish this test suite. This tuple of sequences should # contain at least the values in the Cartesian product of (half-duplex, # full-duplex) * (zero payloads, one payload, test_constants.STREAM_LENGTH # payloads) * (completion, cancellation, expiration, programming defect in # servicer code). SEQUENCES = ( _EASY, _PEASY, ) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py0000644000175000017500000000500012600663151030221 0ustar apollockapollock# 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. """Part of the tests of the base interface of RPC Framework.""" class OperationState(object): def __init__(self): self.invocation_initial_metadata_in_flight = None self.invocation_initial_metadata_received = False self.invocation_payloads_in_flight = [] self.invocation_payloads_received = 0 self.invocation_completion_in_flight = None self.invocation_completion_received = False self.service_initial_metadata_in_flight = None self.service_initial_metadata_received = False self.service_payloads_in_flight = [] self.service_payloads_received = 0 self.service_completion_in_flight = None self.service_completion_received = False self.invocation_side_invocation_allowance = 1 self.invocation_side_service_allowance = 1 self.service_side_invocation_allowance = 1 self.service_side_service_allowance = 1 self.invocation_allowance_in_flight = 0 self.service_allowance_in_flight = 0 self.invocation_side_outcome = None self.service_side_outcome = None grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py0000644000175000017500000000277212600663151030516 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py0000644000175000017500000001417612600663151032142 0ustar apollockapollock# 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. """Interfaces used in tests of implementations of the Base layer.""" import abc from grpc.framework.interfaces.base import base # pylint: disable=unused-import class Serialization(object): """Specifies serialization and deserialization of test payloads.""" __metaclass__ = abc.ABCMeta def serialize_request(self, request): """Serializes a request value used in a test. Args: request: A request value created by a test. Returns: A bytestring that is the serialization of the given request. """ raise NotImplementedError() def deserialize_request(self, serialized_request): """Deserializes a request value used in a test. Args: serialized_request: A bytestring that is the serialization of some request used in a test. Returns: The request value encoded by the given bytestring. """ raise NotImplementedError() def serialize_response(self, response): """Serializes a response value used in a test. Args: response: A response value created by a test. Returns: A bytestring that is the serialization of the given response. """ raise NotImplementedError() def deserialize_response(self, serialized_response): """Deserializes a response value used in a test. Args: serialized_response: A bytestring that is the serialization of some response used in a test. Returns: The response value encoded by the given bytestring. """ raise NotImplementedError() class Implementation(object): """Specifies an implementation of the Base layer.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def instantiate(self, serializations, servicer): """Instantiates the Base layer implementation to be used in a test. Args: serializations: A dict from group-method pair to Serialization object specifying how to serialize and deserialize payload values used in the test. servicer: A base.Servicer object to be called to service RPCs made during the test. Returns: A sequence of length three the first element of which is a base.End to be used to invoke RPCs, the second element of which is a base.End to be used to service invoked RPCs, and the third element of which is an arbitrary memo object to be kept and passed to destantiate at the conclusion of the test. """ raise NotImplementedError() @abc.abstractmethod def destantiate(self, memo): """Destroys the Base layer implementation under test. Args: memo: The object from the third position of the return value of a call to instantiate. """ raise NotImplementedError() @abc.abstractmethod def invocation_initial_metadata(self): """Provides an operation's invocation-side initial metadata. Returns: A value to use for an operation's invocation-side initial metadata, or None. """ raise NotImplementedError() @abc.abstractmethod def service_initial_metadata(self): """Provices an operation's service-side initial metadata. Returns: A value to use for an operation's service-side initial metadata, or None. """ raise NotImplementedError() @abc.abstractmethod def invocation_completion(self): """Provides an operation's invocation-side completion. Returns: A base.Completion to use for an operation's invocation-side completion. """ raise NotImplementedError() @abc.abstractmethod def service_completion(self): """Provides an operation's service-side completion. Returns: A base.Completion to use for an operation's service-side completion. """ raise NotImplementedError() @abc.abstractmethod def metadata_transmitted(self, original_metadata, transmitted_metadata): """Identifies whether or not metadata was properly transmitted. Args: original_metadata: A metadata value passed to the system under test. transmitted_metadata: The same metadata value after having been transmitted through the system under test. Returns: Whether or not the metadata was properly transmitted. """ raise NotImplementedError() @abc.abstractmethod def completion_transmitted(self, original_completion, transmitted_completion): """Identifies whether or not a base.Completion was properly transmitted. Args: original_completion: A base.Completion passed to the system under test. transmitted_completion: The same completion value after having been transmitted through the system under test. Returns: Whether or not the completion was properly transmitted. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py0000644000175000017500000002434712600663151031116 0ustar apollockapollock# 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. """Tests of the base interface of RPC Framework.""" import logging import random import threading import time import unittest from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.base import base from grpc.framework.interfaces.base import utilities from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.base import _control from grpc_test.framework.interfaces.base import test_interfaces _SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True)) _EMPTY_OUTCOME_KIND_DICT = { outcome_kind: 0 for outcome_kind in base.Outcome.Kind} class _Serialization(test_interfaces.Serialization): def serialize_request(self, request): return request + request def deserialize_request(self, serialized_request): return serialized_request[:len(serialized_request) / 2] def serialize_response(self, response): return response * 3 def deserialize_response(self, serialized_response): return serialized_response[2 * len(serialized_response) / 3:] def _advance(quadruples, operator, controller): try: for quadruple in quadruples: operator.advance( initial_metadata=quadruple[0], payload=quadruple[1], completion=quadruple[2], allowance=quadruple[3]) except Exception as e: # pylint: disable=broad-except controller.failed('Exception on advance: %e' % e) class _Operator(base.Operator): def __init__(self, controller, on_advance, pool, operator_under_test): self._condition = threading.Condition() self._controller = controller self._on_advance = on_advance self._pool = pool self._operator_under_test = operator_under_test self._pending_advances = [] def set_operator_under_test(self, operator_under_test): with self._condition: self._operator_under_test = operator_under_test pent_advances = self._pending_advances self._pending_advances = [] pool = self._pool controller = self._controller if pool is None: _advance(pent_advances, operator_under_test, controller) else: pool.submit(_advance, pent_advances, operator_under_test, controller) def advance( self, initial_metadata=None, payload=None, completion=None, allowance=None): on_advance = self._on_advance( initial_metadata, payload, completion, allowance) if on_advance.kind is _control.OnAdvance.Kind.ADVANCE: with self._condition: pool = self._pool operator_under_test = self._operator_under_test controller = self._controller quadruple = ( on_advance.initial_metadata, on_advance.payload, on_advance.completion, on_advance.allowance) if pool is None: _advance((quadruple,), operator_under_test, controller) else: pool.submit(_advance, (quadruple,), operator_under_test, controller) elif on_advance.kind is _control.OnAdvance.Kind.DEFECT: raise ValueError( 'Deliberately raised exception from Operator.advance (in a test)!') class _ProtocolReceiver(base.ProtocolReceiver): def __init__(self): self._condition = threading.Condition() self._contexts = [] def context(self, protocol_context): with self._condition: self._contexts.append(protocol_context) class _Servicer(base.Servicer): """A base.Servicer with instrumented for testing.""" def __init__(self, group, method, controllers, pool): self._condition = threading.Condition() self._group = group self._method = method self._pool = pool self._controllers = list(controllers) def service(self, group, method, context, output_operator): with self._condition: controller = self._controllers.pop(0) if group != self._group or method != self._method: controller.fail( '%s != %s or %s != %s' % (group, self._group, method, self._method)) raise base.NoSuchMethodError(None, None) else: operator = _Operator( controller, controller.on_service_advance, self._pool, output_operator) outcome = context.add_termination_callback( controller.service_on_termination) if outcome is not None: controller.service_on_termination(outcome) return utilities.full_subscription(operator, _ProtocolReceiver()) class _OperationTest(unittest.TestCase): def setUp(self): if self._synchronicity_variation: self._pool = logging_pool.pool(test_constants.POOL_SIZE) else: self._pool = None self._controller = self._controller_creator.controller( self._implementation, self._randomness) def tearDown(self): if self._synchronicity_variation: self._pool.shutdown(wait=True) else: self._pool = None def test_operation(self): invocation = self._controller.invocation() if invocation.subscription_kind is base.Subscription.Kind.FULL: test_operator = _Operator( self._controller, self._controller.on_invocation_advance, self._pool, None) subscription = utilities.full_subscription( test_operator, _ProtocolReceiver()) else: # TODO(nathaniel): support and test other subscription kinds. self.fail('Non-full subscriptions not yet supported!') servicer = _Servicer( invocation.group, invocation.method, (self._controller,), self._pool) invocation_end, service_end, memo = self._implementation.instantiate( {(invocation.group, invocation.method): _Serialization()}, servicer) try: invocation_end.start() service_end.start() operation_context, operator_under_test = invocation_end.operate( invocation.group, invocation.method, subscription, invocation.timeout, initial_metadata=invocation.initial_metadata, payload=invocation.payload, completion=invocation.completion) test_operator.set_operator_under_test(operator_under_test) outcome = operation_context.add_termination_callback( self._controller.invocation_on_termination) if outcome is not None: self._controller.invocation_on_termination(outcome) except Exception as e: # pylint: disable=broad-except self._controller.failed('Exception on invocation: %s' % e) self.fail(e) while True: instruction = self._controller.poll() if instruction.kind is _control.Instruction.Kind.ADVANCE: try: test_operator.advance( *instruction.advance_args, **instruction.advance_kwargs) except Exception as e: # pylint: disable=broad-except self._controller.failed('Exception on instructed advance: %s' % e) elif instruction.kind is _control.Instruction.Kind.CANCEL: try: operation_context.cancel() except Exception as e: # pylint: disable=broad-except self._controller.failed('Exception on cancel: %s' % e) elif instruction.kind is _control.Instruction.Kind.CONCLUDE: break invocation_stop_event = invocation_end.stop(0) service_stop_event = service_end.stop(0) invocation_stop_event.wait() service_stop_event.wait() invocation_stats = invocation_end.operation_stats() service_stats = service_end.operation_stats() self._implementation.destantiate(memo) self.assertTrue( instruction.conclude_success, msg=instruction.conclude_message) expected_invocation_stats = dict(_EMPTY_OUTCOME_KIND_DICT) expected_invocation_stats[ instruction.conclude_invocation_outcome_kind] += 1 self.assertDictEqual(expected_invocation_stats, invocation_stats) expected_service_stats = dict(_EMPTY_OUTCOME_KIND_DICT) expected_service_stats[instruction.conclude_service_outcome_kind] += 1 self.assertDictEqual(expected_service_stats, service_stats) def test_cases(implementation): """Creates unittest.TestCase classes for a given Base implementation. Args: implementation: A test_interfaces.Implementation specifying creation and destruction of the Base implementation under test. Returns: A sequence of subclasses of unittest.TestCase defining tests of the specified Base layer implementation. """ random_seed = hash(time.time()) logging.warning('Random seed for this execution: %s', random_seed) randomness = random.Random(x=random_seed) test_case_classes = [] for synchronicity_variation in _SYNCHRONICITY_VARIATION: for controller_creator in _control.CONTROLLER_CREATORS: name = ''.join( (synchronicity_variation[0], controller_creator.name(), 'Test',)) test_case_classes.append( type(name, (_OperationTest,), {'_implementation': implementation, '_randomness': randomness, '_synchronicity_variation': synchronicity_variation[1], '_controller_creator': controller_creator, })) return test_case_classes grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/0000755000175000017500000000000012600663151024236 5ustar apollockapollock././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/blocking_invocation_inline_service_test.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/blocking_invocation_inline_service_test.0000644000175000017500000000366712600663151034411 0ustar apollockapollock# 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. """One of the tests of the Face layer of RPC Framework.""" import unittest from grpc_test.framework.face import _test_case from grpc_test.framework.face.testing import blocking_invocation_inline_service_test_case as test_case class BlockingInvocationInlineServiceTest( _test_case.FaceTestCase, test_case.BlockingInvocationInlineServiceTestCase, unittest.TestCase): pass if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/0000755000175000017500000000000012600663151025713 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/control.py0000644000175000017500000000576112600663151027756 0ustar apollockapollock# 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. """Code for instructing systems under test to block or fail.""" import abc import contextlib import threading class Control(object): """An object that accepts program control from a system under test. Systems under test passed a Control should call its control() method frequently during execution. The control() method may block, raise an exception, or do nothing, all according to the enclosing test's desire for the system under test to simulate hanging, failing, or functioning. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def control(self): """Potentially does anything.""" raise NotImplementedError() class PauseFailControl(Control): """A Control that can be used to pause or fail code under control.""" def __init__(self): self._condition = threading.Condition() self._paused = False self._fail = False def control(self): with self._condition: if self._fail: raise ValueError() while self._paused: self._condition.wait() @contextlib.contextmanager def pause(self): """Pauses code under control while controlling code is in context.""" with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() @contextlib.contextmanager def fail(self): """Fails code under control while controlling code is in context.""" with self._condition: self._fail = True yield with self._condition: self._fail = False grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py0000644000175000017500000000654412600663151030250 0ustar apollockapollock# 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. """Tools for creating tests of implementations of the Face layer.""" import abc # face_interfaces and interfaces are referenced in specification in this module. from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import from grpc_test.framework.face.testing import interfaces # pylint: disable=unused-import class FaceTestCase(object): """Describes a test of the Face Layer of RPC Framework. Concrete subclasses must also inherit from unittest.TestCase and from at least one class that defines test methods. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_up_implementation( self, name, methods, method_implementations, multi_method_implementation): """Instantiates the Face Layer implementation under test. Args: name: The service name to be used in the test. methods: A sequence of interfaces.Method objects describing the RPC methods that will be called during the test. method_implementations: A dictionary from string RPC method name to face_interfaces.MethodImplementation object specifying implementation of an RPC method. multi_method_implementation: An face_interfaces.MultiMethodImplementation or None. Returns: A sequence of length two the first element of which is a face_interfaces.GenericStub (backed by the given method implementations), and the second element of which is an arbitrary memo object to be kept and passed to tearDownImplementation at the conclusion of the test. """ raise NotImplementedError() @abc.abstractmethod def tear_down_implementation(self, memo): """Destroys the Face layer implementation under test. Args: memo: The object from the second position of the return value of set_up_implementation. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py0000644000175000017500000002763012600663151031140 0ustar apollockapollock# 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. """Examples of Python implementations of the stock.proto Stock service.""" from grpc.framework.common import cardinality from grpc.framework.foundation import abandonment from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util from grpc_test.framework.face.testing import service from grpc_test._junkdrawer import stock_pb2 SYMBOL_FORMAT = 'test symbol:%03d' STREAM_LENGTH = 400 # A test-appropriate security-pricing function. :-P _price = lambda symbol_name: float(hash(symbol_name) % 4096) def _get_last_trade_price(stock_request, stock_reply_callback, control, active): """A unary-request, unary-response test method.""" control.control() if active(): stock_reply_callback( stock_pb2.StockReply( symbol=stock_request.symbol, price=_price(stock_request.symbol))) else: raise abandonment.Abandoned() def _get_last_trade_price_multiple(stock_reply_consumer, control, active): """A stream-request, stream-response test method.""" def stock_reply_for_stock_request(stock_request): control.control() if active(): return stock_pb2.StockReply( symbol=stock_request.symbol, price=_price(stock_request.symbol)) else: raise abandonment.Abandoned() return stream_util.TransformingConsumer( stock_reply_for_stock_request, stock_reply_consumer) def _watch_future_trades(stock_request, stock_reply_consumer, control, active): """A unary-request, stream-response test method.""" base_price = _price(stock_request.symbol) for index in range(stock_request.num_trades_to_watch): control.control() if active(): stock_reply_consumer.consume( stock_pb2.StockReply( symbol=stock_request.symbol, price=base_price + index)) else: raise abandonment.Abandoned() stock_reply_consumer.terminate() def _get_highest_trade_price(stock_reply_callback, control, active): """A stream-request, unary-response test method.""" class StockRequestConsumer(stream.Consumer): """Keeps an ongoing record of the most valuable symbol yet consumed.""" def __init__(self): self._symbol = None self._price = None def consume(self, stock_request): control.control() if active(): if self._price is None: self._symbol = stock_request.symbol self._price = _price(stock_request.symbol) else: candidate_price = _price(stock_request.symbol) if self._price < candidate_price: self._symbol = stock_request.symbol self._price = candidate_price def terminate(self): control.control() if active(): if self._symbol is None: raise ValueError() else: stock_reply_callback( stock_pb2.StockReply(symbol=self._symbol, price=self._price)) self._symbol = None self._price = None def consume_and_terminate(self, stock_request): control.control() if active(): if self._price is None: stock_reply_callback( stock_pb2.StockReply( symbol=stock_request.symbol, price=_price(stock_request.symbol))) else: candidate_price = _price(stock_request.symbol) if self._price < candidate_price: stock_reply_callback( stock_pb2.StockReply( symbol=stock_request.symbol, price=candidate_price)) else: stock_reply_callback( stock_pb2.StockReply( symbol=self._symbol, price=self._price)) self._symbol = None self._price = None return StockRequestConsumer() class GetLastTradePrice(service.UnaryUnaryTestMethodImplementation): """GetLastTradePrice for use in tests.""" def name(self): return 'GetLastTradePrice' def cardinality(self): return cardinality.Cardinality.UNARY_UNARY def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, request, response_callback, context, control): _get_last_trade_price( request, response_callback, control, context.is_active) class GetLastTradePriceMessages(service.UnaryUnaryTestMessages): def __init__(self): self._index = 0 def request(self): symbol = SYMBOL_FORMAT % self._index self._index += 1 return stock_pb2.StockRequest(symbol=symbol) def verify(self, request, response, test_case): test_case.assertEqual(request.symbol, response.symbol) test_case.assertEqual(_price(request.symbol), response.price) class GetLastTradePriceMultiple(service.StreamStreamTestMethodImplementation): """GetLastTradePriceMultiple for use in tests.""" def name(self): return 'GetLastTradePriceMultiple' def cardinality(self): return cardinality.Cardinality.STREAM_STREAM def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, response_consumer, context, control): return _get_last_trade_price_multiple( response_consumer, control, context.is_active) class GetLastTradePriceMultipleMessages(service.StreamStreamTestMessages): """Pairs of message streams for use with GetLastTradePriceMultiple.""" def __init__(self): self._index = 0 def requests(self): base_index = self._index self._index += 1 return [ stock_pb2.StockRequest(symbol=SYMBOL_FORMAT % (base_index + index)) for index in range(STREAM_LENGTH)] def verify(self, requests, responses, test_case): test_case.assertEqual(len(requests), len(responses)) for stock_request, stock_reply in zip(requests, responses): test_case.assertEqual(stock_request.symbol, stock_reply.symbol) test_case.assertEqual(_price(stock_request.symbol), stock_reply.price) class WatchFutureTrades(service.UnaryStreamTestMethodImplementation): """WatchFutureTrades for use in tests.""" def name(self): return 'WatchFutureTrades' def cardinality(self): return cardinality.Cardinality.UNARY_STREAM def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, request, response_consumer, context, control): _watch_future_trades(request, response_consumer, control, context.is_active) class WatchFutureTradesMessages(service.UnaryStreamTestMessages): """Pairs of a single request message and a sequence of response messages.""" def __init__(self): self._index = 0 def request(self): symbol = SYMBOL_FORMAT % self._index self._index += 1 return stock_pb2.StockRequest( symbol=symbol, num_trades_to_watch=STREAM_LENGTH) def verify(self, request, responses, test_case): test_case.assertEqual(STREAM_LENGTH, len(responses)) base_price = _price(request.symbol) for index, response in enumerate(responses): test_case.assertEqual(base_price + index, response.price) class GetHighestTradePrice(service.StreamUnaryTestMethodImplementation): """GetHighestTradePrice for use in tests.""" def name(self): return 'GetHighestTradePrice' def cardinality(self): return cardinality.Cardinality.STREAM_UNARY def request_class(self): return stock_pb2.StockRequest def response_class(self): return stock_pb2.StockReply def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, serialized_request): return stock_pb2.StockRequest.FromString(serialized_request) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, serialized_response): return stock_pb2.StockReply.FromString(serialized_response) def service(self, response_callback, context, control): return _get_highest_trade_price( response_callback, control, context.is_active) class GetHighestTradePriceMessages(service.StreamUnaryTestMessages): def requests(self): return [ stock_pb2.StockRequest(symbol=SYMBOL_FORMAT % index) for index in range(STREAM_LENGTH)] def verify(self, requests, response, test_case): price = None symbol = None for stock_request in requests: current_symbol = stock_request.symbol current_price = _price(current_symbol) if price is None or price < current_price: price = current_price symbol = current_symbol test_case.assertEqual(price, response.price) test_case.assertEqual(symbol, response.symbol) class StockTestService(service.TestService): """A corpus of test data with one method of each RPC cardinality.""" def name(self): return 'Stock' def unary_unary_scenarios(self): return { 'GetLastTradePrice': ( GetLastTradePrice(), [GetLastTradePriceMessages()]), } def unary_stream_scenarios(self): return { 'WatchFutureTrades': ( WatchFutureTrades(), [WatchFutureTradesMessages()]), } def stream_unary_scenarios(self): return { 'GetHighestTradePrice': ( GetHighestTradePrice(), [GetHighestTradePriceMessages()]) } def stream_stream_scenarios(self): return { 'GetLastTradePriceMultiple': ( GetLastTradePriceMultiple(), [GetLastTradePriceMultipleMessages()]), } STOCK_TEST_SERVICE = StockTestService() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py0000644000175000017500000000741112600663151030413 0ustar apollockapollock# 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. """Interfaces implemented by data sets used in Face-layer tests.""" import abc # cardinality is referenced from specification in this module. from grpc.framework.common import cardinality # pylint: disable=unused-import class Method(object): """An RPC method to be used in tests of RPC implementations.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def name(self): """Identify the name of the method. Returns: The name of the method. """ raise NotImplementedError() @abc.abstractmethod def cardinality(self): """Identify the cardinality of the method. Returns: A cardinality.Cardinality value describing the streaming semantics of the method. """ raise NotImplementedError() @abc.abstractmethod def request_class(self): """Identify the class used for the method's request objects. Returns: The class object of the class to which the method's request objects belong. """ raise NotImplementedError() @abc.abstractmethod def response_class(self): """Identify the class used for the method's response objects. Returns: The class object of the class to which the method's response objects belong. """ raise NotImplementedError() @abc.abstractmethod def serialize_request(self, request): """Serialize the given request object. Args: request: A request object appropriate for this method. """ raise NotImplementedError() @abc.abstractmethod def deserialize_request(self, serialized_request): """Synthesize a request object from a given bytestring. Args: serialized_request: A bytestring deserializable into a request object appropriate for this method. """ raise NotImplementedError() @abc.abstractmethod def serialize_response(self, response): """Serialize the given response object. Args: response: A response object appropriate for this method. """ raise NotImplementedError() @abc.abstractmethod def deserialize_response(self, serialized_response): """Synthesize a response object from a given bytestring. Args: serialized_response: A bytestring deserializable into a response object appropriate for this method. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/serial.py0000644000175000017500000000560312600663151027550 0ustar apollockapollock# 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. """Utility for serialization in the context of test RPC services.""" import collections class Serialization( collections.namedtuple( '_Serialization', ['request_serializers', 'request_deserializers', 'response_serializers', 'response_deserializers'])): """An aggregation of serialization behaviors for an RPC service. Attributes: request_serializers: A dict from method name to request object serializer behavior. request_deserializers: A dict from method name to request object deserializer behavior. response_serializers: A dict from method name to response object serializer behavior. response_deserializers: A dict from method name to response object deserializer behavior. """ def serialization(methods): """Creates a Serialization from a sequences of interfaces.Method objects.""" request_serializers = {} request_deserializers = {} response_serializers = {} response_deserializers = {} for method in methods: name = method.name() request_serializers[name] = method.serialize_request request_deserializers[name] = method.deserialize_request response_serializers[name] = method.serialize_response response_deserializers[name] = method.deserialize_response return Serialization( request_serializers, request_deserializers, response_serializers, response_deserializers) ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_servi0000644000175000017500000002240612600663151034431 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A test to verify an implementation of the Face layer of RPC Framework.""" # unittest is referenced from specification in this module. import abc import unittest # pylint: disable=unused-import from grpc.framework.face import exceptions from grpc_test.framework.common import test_constants from grpc_test.framework.face.testing import control from grpc_test.framework.face.testing import coverage from grpc_test.framework.face.testing import digest from grpc_test.framework.face.testing import stock_service from grpc_test.framework.face.testing import test_case class BlockingInvocationInlineServiceTestCase( test_case.FaceTestCase, coverage.BlockingCoverage): """A test of the Face layer of RPC Framework. Concrete subclasses must also extend unittest.TestCase. """ __metaclass__ = abc.ABCMeta def setUp(self): """See unittest.TestCase.setUp for full specification. Overriding implementations must call this implementation. """ self.control = control.PauseFailControl() self.digest = digest.digest( stock_service.STOCK_TEST_SERVICE, self.control, None) self.stub, self.memo = self.set_up_implementation( self.digest.name, self.digest.methods, self.digest.inline_method_implementations, None) def tearDown(self): """See unittest.TestCase.tearDown for full specification. Overriding implementations must call this implementation. """ self.tear_down_implementation(self.memo) def testSuccessfulUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response = self.stub.blocking_value_in_value_out( name, request, test_constants.LONG_TIMEOUT) test_messages.verify(request, response, self) def testSuccessfulUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(request, responses, self) def testSuccessfulStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() response = self.stub.blocking_stream_in_value_out( name, iter(requests), test_constants.LONG_TIMEOUT) test_messages.verify(requests, response, self) def testSuccessfulStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() response_iterator = self.stub.inline_stream_in_stream_out( name, iter(requests), test_constants.LONG_TIMEOUT) responses = list(response_iterator) test_messages.verify(requests, responses, self) def testSequentialInvocations(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() first_response = self.stub.blocking_value_in_value_out( name, first_request, test_constants.SHORT_TIMEOUT) test_messages.verify(first_request, first_response, self) second_response = self.stub.blocking_value_in_value_out( name, second_request, test_constants.SHORT_TIMEOUT) test_messages.verify(second_request, second_response, self) def testExpiredUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.pause(), self.assertRaises( exceptions.ExpirationError): multi_callable = self.stub.unary_unary_multi_callable(name) multi_callable(request, test_constants.SHORT_TIMEOUT) def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.pause(), self.assertRaises( exceptions.ExpirationError): response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.SHORT_TIMEOUT) list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.pause(), self.assertRaises( exceptions.ExpirationError): multi_callable = self.stub.stream_unary_multi_callable(name) multi_callable(iter(requests), test_constants.SHORT_TIMEOUT) def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.pause(), self.assertRaises( exceptions.ExpirationError): response_iterator = self.stub.inline_stream_in_stream_out( name, iter(requests), test_constants.SHORT_TIMEOUT) list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.fail(), self.assertRaises(exceptions.ServicerError): self.stub.blocking_value_in_value_out(name, request, test_constants.SHORT_TIMEOUT) def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.fail(), self.assertRaises(exceptions.ServicerError): response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.fail(), self.assertRaises(exceptions.ServicerError): self.stub.blocking_stream_in_value_out(name, iter(requests), test_constants.SHORT_TIMEOUT) def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.fail(), self.assertRaises(exceptions.ServicerError): response_iterator = self.stub.inline_stream_in_stream_out( name, iter(requests), test_constants.SHORT_TIMEOUT) list(response_iterator) ././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_eve0000644000175000017500000003645212600663151034533 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A test to verify an implementation of the Face layer of RPC Framework.""" import abc import unittest from grpc.framework.face import interfaces from grpc_test.framework.common import test_constants from grpc_test.framework.face.testing import callback as testing_callback from grpc_test.framework.face.testing import control from grpc_test.framework.face.testing import coverage from grpc_test.framework.face.testing import digest from grpc_test.framework.face.testing import stock_service from grpc_test.framework.face.testing import test_case class EventInvocationSynchronousEventServiceTestCase( test_case.FaceTestCase, coverage.FullCoverage): """A test of the Face layer of RPC Framework. Concrete subclasses must also extend unittest.TestCase. """ __metaclass__ = abc.ABCMeta def setUp(self): """See unittest.TestCase.setUp for full specification. Overriding implementations must call this implementation. """ self.control = control.PauseFailControl() self.digest = digest.digest( stock_service.STOCK_TEST_SERVICE, self.control, None) self.stub, self.memo = self.set_up_implementation( self.digest.name, self.digest.methods, self.digest.event_method_implementations, None) def tearDown(self): """See unittest.TestCase.tearDown for full specification. Overriding implementations must call this implementation. """ self.tear_down_implementation(self.memo) def testSuccessfulUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() self.stub.event_value_in_value_out( name, request, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() response = callback.response() test_messages.verify(request, response, self) def testSuccessfulUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() self.stub.event_value_in_stream_out( name, request, callback, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() responses = callback.responses() test_messages.verify(request, responses, self) def testSuccessfulStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() unused_call, request_consumer = self.stub.event_stream_in_value_out( name, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() callback.block_until_terminated() response = callback.response() test_messages.verify(requests, response, self) def testSuccessfulStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() unused_call, request_consumer = self.stub.event_stream_in_stream_out( name, callback, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() callback.block_until_terminated() responses = callback.responses() test_messages.verify(requests, responses, self) def testSequentialInvocations(self): # pylint: disable=cell-var-from-loop for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() first_callback = testing_callback.Callback() second_callback = testing_callback.Callback() def make_second_invocation(first_response): first_callback.complete(first_response) self.stub.event_value_in_value_out( name, second_request, second_callback.complete, second_callback.abort, test_constants.SHORT_TIMEOUT) self.stub.event_value_in_value_out( name, first_request, make_second_invocation, first_callback.abort, test_constants.SHORT_TIMEOUT) second_callback.block_until_terminated() first_response = first_callback.response() second_response = second_callback.response() test_messages.verify(first_request, first_response, self) test_messages.verify(second_request, second_response, self) def testExpiredUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() with self.control.pause(): self.stub.event_value_in_value_out( name, request, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() with self.control.pause(): self.stub.event_value_in_stream_out( name, request, callback, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) def testExpiredStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for unused_test_messages in test_messages_sequence: callback = testing_callback.Callback() self.stub.event_stream_in_value_out( name, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() unused_call, request_consumer = self.stub.event_stream_in_stream_out( name, callback, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion()) def testFailedUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() with self.control.fail(): self.stub.event_value_in_value_out( name, request, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() with self.control.fail(): self.stub.event_value_in_stream_out( name, request, callback, callback.abort, test_constants.SHORT_TIMEOUT) callback.block_until_terminated() self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() with self.control.fail(): unused_call, request_consumer = self.stub.event_stream_in_value_out( name, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() callback.block_until_terminated() self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() with self.control.fail(): unused_call, request_consumer = self.stub.event_stream_in_stream_out( name, callback, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) request_consumer.terminate() callback.block_until_terminated() self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion()) def testParallelInvocations(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() first_callback = testing_callback.Callback() second_request = test_messages.request() second_callback = testing_callback.Callback() self.stub.event_value_in_value_out( name, first_request, first_callback.complete, first_callback.abort, test_constants.SHORT_TIMEOUT) self.stub.event_value_in_value_out( name, second_request, second_callback.complete, second_callback.abort, test_constants.SHORT_TIMEOUT) first_callback.block_until_terminated() second_callback.block_until_terminated() first_response = first_callback.response() second_response = second_callback.response() test_messages.verify(first_request, first_response, self) test_messages.verify(second_request, second_response, self) @unittest.skip('TODO(nathaniel): implement.') def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() def testCancelledUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() with self.control.pause(): call = self.stub.event_value_in_value_out( name, request, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) call.cancel() callback.block_until_terminated() self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion()) def testCancelledUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() callback = testing_callback.Callback() call = self.stub.event_value_in_stream_out( name, request, callback, callback.abort, test_constants.SHORT_TIMEOUT) call.cancel() callback.block_until_terminated() self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion()) def testCancelledStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() callback = testing_callback.Callback() call, request_consumer = self.stub.event_stream_in_value_out( name, callback.complete, callback.abort, test_constants.SHORT_TIMEOUT) for request in requests: request_consumer.consume(request) call.cancel() callback.block_until_terminated() self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion()) def testCancelledStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for unused_test_messages in test_messages_sequence: callback = testing_callback.Callback() call, unused_request_consumer = self.stub.event_stream_in_stream_out( name, callback, callback.abort, test_constants.SHORT_TIMEOUT) call.cancel() callback.block_until_terminated() self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion()) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/service.py0000644000175000017500000002654112600663151027735 0ustar apollockapollock# 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. """Private interfaces implemented by data sets used in Face-layer tests.""" import abc # interfaces is referenced from specification in this module. from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import from grpc_test.framework.face.testing import interfaces class UnaryUnaryTestMethodImplementation(interfaces.Method): """A controllable implementation of a unary-unary RPC method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, request, response_callback, context, control): """Services an RPC that accepts one message and produces one message. Args: request: The single request message for the RPC. response_callback: A callback to be called to accept the response message of the RPC. context: An face_interfaces.RpcContext object. control: A test_control.Control to control execution of this method. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class UnaryUnaryTestMessages(object): """A type for unary-request-unary-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def request(self): """Affords a request message. Implementations of this method should return a different message with each call so that multiple test executions of the test method may be made with different inputs. Returns: A request message. """ raise NotImplementedError() @abc.abstractmethod def verify(self, request, response, test_case): """Verifies that the computed response matches the given request. Args: request: A request message. response: A response message. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the request and response do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class UnaryStreamTestMethodImplementation(interfaces.Method): """A controllable implementation of a unary-stream RPC method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, request, response_consumer, context, control): """Services an RPC that takes one message and produces a stream of messages. Args: request: The single request message for the RPC. response_consumer: A stream.Consumer to be called to accept the response messages of the RPC. context: A face_interfaces.RpcContext object. control: A test_control.Control to control execution of this method. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class UnaryStreamTestMessages(object): """A type for unary-request-stream-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def request(self): """Affords a request message. Implementations of this method should return a different message with each call so that multiple test executions of the test method may be made with different inputs. Returns: A request message. """ raise NotImplementedError() @abc.abstractmethod def verify(self, request, responses, test_case): """Verifies that the computed responses match the given request. Args: request: A request message. responses: A sequence of response messages. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the request and responses do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class StreamUnaryTestMethodImplementation(interfaces.Method): """A controllable implementation of a stream-unary RPC method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, response_callback, context, control): """Services an RPC that takes a stream of messages and produces one message. Args: response_callback: A callback to be called to accept the response message of the RPC. context: A face_interfaces.RpcContext object. control: A test_control.Control to control execution of this method. Returns: A stream.Consumer with which to accept the request messages of the RPC. The consumer returned from this method may or may not be invoked to completion: in the case of RPC abortion, RPC Framework will simply stop passing messages to this object. Implementations must not assume that this object will be called to completion of the request stream or even called at all. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class StreamUnaryTestMessages(object): """A type for stream-request-unary-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def requests(self): """Affords a sequence of request messages. Implementations of this method should return a different sequences with each call so that multiple test executions of the test method may be made with different inputs. Returns: A sequence of request messages. """ raise NotImplementedError() @abc.abstractmethod def verify(self, requests, response, test_case): """Verifies that the computed response matches the given requests. Args: requests: A sequence of request messages. response: A response message. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the requests and response do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class StreamStreamTestMethodImplementation(interfaces.Method): """A controllable implementation of a stream-stream RPC method.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def service(self, response_consumer, context, control): """Services an RPC that accepts and produces streams of messages. Args: response_consumer: A stream.Consumer to be called to accept the response messages of the RPC. context: A face_interfaces.RpcContext object. control: A test_control.Control to control execution of this method. Returns: A stream.Consumer with which to accept the request messages of the RPC. The consumer returned from this method may or may not be invoked to completion: in the case of RPC abortion, RPC Framework will simply stop passing messages to this object. Implementations must not assume that this object will be called to completion of the request stream or even called at all. Raises: abandonment.Abandoned: May or may not be raised when the RPC has been aborted. """ raise NotImplementedError() class StreamStreamTestMessages(object): """A type for stream-request-stream-response message pairings.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def requests(self): """Affords a sequence of request messages. Implementations of this method should return a different sequences with each call so that multiple test executions of the test method may be made with different inputs. Returns: A sequence of request messages. """ raise NotImplementedError() @abc.abstractmethod def verify(self, requests, responses, test_case): """Verifies that the computed response matches the given requests. Args: requests: A sequence of request messages. responses: A sequence of response messages. test_case: A unittest.TestCase object affording useful assertion methods. Raises: AssertionError: If the requests and responses do not match, indicating that there was some problem executing the RPC under test. """ raise NotImplementedError() class TestService(object): """A specification of implemented RPC methods to use in tests.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def name(self): """Identifies the RPC service name used during the test. Returns: The RPC service name to be used for the test. """ raise NotImplementedError() @abc.abstractmethod def unary_unary_scenarios(self): """Affords unary-request-unary-response test methods and their messages. Returns: A dict from method name to pair. The first element of the pair is a UnaryUnaryTestMethodImplementation object and the second element is a sequence of UnaryUnaryTestMethodMessages objects. """ raise NotImplementedError() @abc.abstractmethod def unary_stream_scenarios(self): """Affords unary-request-stream-response test methods and their messages. Returns: A dict from method name to pair. The first element of the pair is a UnaryStreamTestMethodImplementation object and the second element is a sequence of UnaryStreamTestMethodMessages objects. """ raise NotImplementedError() @abc.abstractmethod def stream_unary_scenarios(self): """Affords stream-request-unary-response test methods and their messages. Returns: A dict from method name to pair. The first element of the pair is a StreamUnaryTestMethodImplementation object and the second element is a sequence of StreamUnaryTestMethodMessages objects. """ raise NotImplementedError() @abc.abstractmethod def stream_stream_scenarios(self): """Affords stream-request-stream-response test methods and their messages. Returns: A dict from method name to pair. The first element of the pair is a StreamStreamTestMethodImplementation object and the second element is a sequence of StreamStreamTestMethodMessages objects. """ raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py0000644000175000017500000003677012600663151027561 0ustar apollockapollock# 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. """Code for making a service.TestService more amenable to use in tests.""" import collections import threading # testing_control, interfaces, and testing_service are referenced from # specification in this module. from grpc.framework.common import cardinality from grpc.framework.common import style from grpc.framework.face import exceptions from grpc.framework.face import interfaces as face_interfaces from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util from grpc_test.framework.face.testing import control as testing_control # pylint: disable=unused-import from grpc_test.framework.face.testing import interfaces # pylint: disable=unused-import from grpc_test.framework.face.testing import service as testing_service # pylint: disable=unused-import _IDENTITY = lambda x: x class TestServiceDigest( collections.namedtuple( 'TestServiceDigest', ['name', 'methods', 'inline_method_implementations', 'event_method_implementations', 'multi_method_implementation', 'unary_unary_messages_sequences', 'unary_stream_messages_sequences', 'stream_unary_messages_sequences', 'stream_stream_messages_sequences'])): """A transformation of a service.TestService. Attributes: name: The RPC service name to be used in the test. methods: A sequence of interfaces.Method objects describing the RPC methods that will be called during the test. inline_method_implementations: A dict from RPC method name to face_interfaces.MethodImplementation object to be used in tests of in-line calls to behaviors under test. event_method_implementations: A dict from RPC method name to face_interfaces.MethodImplementation object to be used in tests of event-driven calls to behaviors under test. multi_method_implementation: A face_interfaces.MultiMethodImplementation to be used in tests of generic calls to behaviors under test. unary_unary_messages_sequences: A dict from method name to sequence of service.UnaryUnaryTestMessages objects to be used to test the method with the given name. unary_stream_messages_sequences: A dict from method name to sequence of service.UnaryStreamTestMessages objects to be used to test the method with the given name. stream_unary_messages_sequences: A dict from method name to sequence of service.StreamUnaryTestMessages objects to be used to test the method with the given name. stream_stream_messages_sequences: A dict from method name to sequence of service.StreamStreamTestMessages objects to be used to test the method with the given name. serialization: A serial.Serialization object describing serialization behaviors for all the RPC methods. """ class _BufferingConsumer(stream.Consumer): """A trivial Consumer that dumps what it consumes in a user-mutable buffer.""" def __init__(self): self.consumed = [] self.terminated = False def consume(self, value): self.consumed.append(value) def terminate(self): self.terminated = True def consume_and_terminate(self, value): self.consumed.append(value) self.terminated = True class _InlineUnaryUnaryMethod(face_interfaces.MethodImplementation): def __init__(self, unary_unary_test_method, control): self._test_method = unary_unary_test_method self._control = control self.cardinality = cardinality.Cardinality.UNARY_UNARY self.style = style.Service.INLINE def unary_unary_inline(self, request, context): response_list = [] self._test_method.service( request, response_list.append, context, self._control) return response_list.pop(0) class _EventUnaryUnaryMethod(face_interfaces.MethodImplementation): def __init__(self, unary_unary_test_method, control, pool): self._test_method = unary_unary_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.UNARY_UNARY self.style = style.Service.EVENT def unary_unary_event(self, request, response_callback, context): if self._pool is None: self._test_method.service( request, response_callback, context, self._control) else: self._pool.submit( self._test_method.service, request, response_callback, context, self._control) class _InlineUnaryStreamMethod(face_interfaces.MethodImplementation): def __init__(self, unary_stream_test_method, control): self._test_method = unary_stream_test_method self._control = control self.cardinality = cardinality.Cardinality.UNARY_STREAM self.style = style.Service.INLINE def unary_stream_inline(self, request, context): response_consumer = _BufferingConsumer() self._test_method.service( request, response_consumer, context, self._control) for response in response_consumer.consumed: yield response class _EventUnaryStreamMethod(face_interfaces.MethodImplementation): def __init__(self, unary_stream_test_method, control, pool): self._test_method = unary_stream_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.UNARY_STREAM self.style = style.Service.EVENT def unary_stream_event(self, request, response_consumer, context): if self._pool is None: self._test_method.service( request, response_consumer, context, self._control) else: self._pool.submit( self._test_method.service, request, response_consumer, context, self._control) class _InlineStreamUnaryMethod(face_interfaces.MethodImplementation): def __init__(self, stream_unary_test_method, control): self._test_method = stream_unary_test_method self._control = control self.cardinality = cardinality.Cardinality.STREAM_UNARY self.style = style.Service.INLINE def stream_unary_inline(self, request_iterator, context): response_list = [] request_consumer = self._test_method.service( response_list.append, context, self._control) for request in request_iterator: request_consumer.consume(request) request_consumer.terminate() return response_list.pop(0) class _EventStreamUnaryMethod(face_interfaces.MethodImplementation): def __init__(self, stream_unary_test_method, control, pool): self._test_method = stream_unary_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.STREAM_UNARY self.style = style.Service.EVENT def stream_unary_event(self, response_callback, context): request_consumer = self._test_method.service( response_callback, context, self._control) if self._pool is None: return request_consumer else: return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool) class _InlineStreamStreamMethod(face_interfaces.MethodImplementation): def __init__(self, stream_stream_test_method, control): self._test_method = stream_stream_test_method self._control = control self.cardinality = cardinality.Cardinality.STREAM_STREAM self.style = style.Service.INLINE def stream_stream_inline(self, request_iterator, context): response_consumer = _BufferingConsumer() request_consumer = self._test_method.service( response_consumer, context, self._control) for request in request_iterator: request_consumer.consume(request) while response_consumer.consumed: yield response_consumer.consumed.pop(0) response_consumer.terminate() class _EventStreamStreamMethod(face_interfaces.MethodImplementation): def __init__(self, stream_stream_test_method, control, pool): self._test_method = stream_stream_test_method self._control = control self._pool = pool self.cardinality = cardinality.Cardinality.STREAM_STREAM self.style = style.Service.EVENT def stream_stream_event(self, response_consumer, context): request_consumer = self._test_method.service( response_consumer, context, self._control) if self._pool is None: return request_consumer else: return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool) class _UnaryConsumer(stream.Consumer): """A Consumer that only allows consumption of exactly one value.""" def __init__(self, action): self._lock = threading.Lock() self._action = action self._consumed = False self._terminated = False def consume(self, value): with self._lock: if self._consumed: raise ValueError('Unary consumer already consumed!') elif self._terminated: raise ValueError('Unary consumer already terminated!') else: self._consumed = True self._action(value) def terminate(self): with self._lock: if not self._consumed: raise ValueError('Unary consumer hasn\'t yet consumed!') elif self._terminated: raise ValueError('Unary consumer already terminated!') else: self._terminated = True def consume_and_terminate(self, value): with self._lock: if self._consumed: raise ValueError('Unary consumer already consumed!') elif self._terminated: raise ValueError('Unary consumer already terminated!') else: self._consumed = True self._terminated = True self._action(value) class _UnaryUnaryAdaptation(object): def __init__(self, unary_unary_test_method): self._method = unary_unary_test_method def service(self, response_consumer, context, control): def action(request): self._method.service( request, response_consumer.consume_and_terminate, context, control) return _UnaryConsumer(action) class _UnaryStreamAdaptation(object): def __init__(self, unary_stream_test_method): self._method = unary_stream_test_method def service(self, response_consumer, context, control): def action(request): self._method.service(request, response_consumer, context, control) return _UnaryConsumer(action) class _StreamUnaryAdaptation(object): def __init__(self, stream_unary_test_method): self._method = stream_unary_test_method def service(self, response_consumer, context, control): return self._method.service( response_consumer.consume_and_terminate, context, control) class _MultiMethodImplementation(face_interfaces.MultiMethodImplementation): def __init__(self, methods, control, pool): self._methods = methods self._control = control self._pool = pool def service(self, name, response_consumer, context): method = self._methods.get(name, None) if method is None: raise exceptions.NoSuchMethodError(name) elif self._pool is None: return method(response_consumer, context, self._control) else: request_consumer = method(response_consumer, context, self._control) return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool) class _Assembly( collections.namedtuple( '_Assembly', ['methods', 'inlines', 'events', 'adaptations', 'messages'])): """An intermediate structure created when creating a TestServiceDigest.""" def _assemble( scenarios, names, inline_method_constructor, event_method_constructor, adapter, control, pool): """Creates an _Assembly from the given scenarios.""" methods = [] inlines = {} events = {} adaptations = {} messages = {} for name, scenario in scenarios.iteritems(): if name in names: raise ValueError('Repeated name "%s"!' % name) test_method = scenario[0] inline_method = inline_method_constructor(test_method, control) event_method = event_method_constructor(test_method, control, pool) adaptation = adapter(test_method) methods.append(test_method) inlines[name] = inline_method events[name] = event_method adaptations[name] = adaptation messages[name] = scenario[1] return _Assembly(methods, inlines, events, adaptations, messages) def digest(service, control, pool): """Creates a TestServiceDigest from a TestService. Args: service: A testing_service.TestService. control: A testing_control.Control. pool: If RPC methods should be serviced in a separate thread, a thread pool. None if RPC methods should be serviced in the thread belonging to the run-time that calls for their service. Returns: A TestServiceDigest synthesized from the given service.TestService. """ names = set() unary_unary = _assemble( service.unary_unary_scenarios(), names, _InlineUnaryUnaryMethod, _EventUnaryUnaryMethod, _UnaryUnaryAdaptation, control, pool) names.update(set(unary_unary.inlines)) unary_stream = _assemble( service.unary_stream_scenarios(), names, _InlineUnaryStreamMethod, _EventUnaryStreamMethod, _UnaryStreamAdaptation, control, pool) names.update(set(unary_stream.inlines)) stream_unary = _assemble( service.stream_unary_scenarios(), names, _InlineStreamUnaryMethod, _EventStreamUnaryMethod, _StreamUnaryAdaptation, control, pool) names.update(set(stream_unary.inlines)) stream_stream = _assemble( service.stream_stream_scenarios(), names, _InlineStreamStreamMethod, _EventStreamStreamMethod, _IDENTITY, control, pool) names.update(set(stream_stream.inlines)) methods = list(unary_unary.methods) methods.extend(unary_stream.methods) methods.extend(stream_unary.methods) methods.extend(stream_stream.methods) adaptations = dict(unary_unary.adaptations) adaptations.update(unary_stream.adaptations) adaptations.update(stream_unary.adaptations) adaptations.update(stream_stream.adaptations) inlines = dict(unary_unary.inlines) inlines.update(unary_stream.inlines) inlines.update(stream_unary.inlines) inlines.update(stream_stream.inlines) events = dict(unary_unary.events) events.update(unary_stream.events) events.update(stream_unary.events) events.update(stream_stream.events) return TestServiceDigest( service.name(), methods, inlines, events, _MultiMethodImplementation(adaptations, control, pool), unary_unary.messages, unary_stream.messages, stream_unary.messages, stream_stream.messages) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py0000644000175000017500000000277212600663151030034 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/callback.py0000644000175000017500000000642012600663151030023 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A utility useful in tests of asynchronous, event-driven interfaces.""" import threading from grpc.framework.foundation import stream class Callback(stream.Consumer): """A utility object useful in tests of asynchronous code.""" def __init__(self): self._condition = threading.Condition() self._unary_response = None self._streamed_responses = [] self._completed = False self._abortion = None def abort(self, abortion): with self._condition: self._abortion = abortion self._condition.notify_all() def complete(self, unary_response): with self._condition: self._unary_response = unary_response self._completed = True self._condition.notify_all() def consume(self, streamed_response): with self._condition: self._streamed_responses.append(streamed_response) def terminate(self): with self._condition: self._completed = True self._condition.notify_all() def consume_and_terminate(self, streamed_response): with self._condition: self._streamed_responses.append(streamed_response) self._completed = True self._condition.notify_all() def block_until_terminated(self): with self._condition: while self._abortion is None and not self._completed: self._condition.wait() def response(self): with self._condition: if self._abortion is None: return self._unary_response else: raise AssertionError('Aborted with abortion "%s"!' % self._abortion) def responses(self): with self._condition: if self._abortion is None: return list(self._streamed_responses) else: raise AssertionError('Aborted with abortion "%s"!' % self._abortion) def abortion(self): with self._condition: return self._abortion grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py0000644000175000017500000000726112600663151030242 0ustar apollockapollock# 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. """Utilities for creating Base-layer objects for use in Face-layer tests.""" import abc # interfaces is referenced from specification in this module. from grpc.framework.base import util as _base_util from grpc.framework.base import implementations from grpc.framework.base import in_memory from grpc.framework.base import interfaces # pylint: disable=unused-import from grpc.framework.foundation import logging_pool _POOL_SIZE_LIMIT = 5 _MAXIMUM_TIMEOUT = 90 class LinkedPair(object): """A Front and Back that are linked to one another. Attributes: front: An interfaces.Front. back: An interfaces.Back. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def shut_down(self): """Shuts down this object and releases its resources.""" raise NotImplementedError() class _LinkedPair(LinkedPair): def __init__(self, front, back, pools): self.front = front self.back = back self._pools = pools def shut_down(self): _base_util.wait_for_idle(self.front) _base_util.wait_for_idle(self.back) for pool in self._pools: pool.shutdown(wait=True) def linked_pair(servicer, default_timeout): """Creates a Server and Stub linked together for use.""" link_pool = logging_pool.pool(_POOL_SIZE_LIMIT) front_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT) front_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT) front_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT) back_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT) back_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT) back_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT) pools = ( link_pool, front_work_pool, front_transmission_pool, front_utility_pool, back_work_pool, back_transmission_pool, back_utility_pool) link = in_memory.Link(link_pool) front = implementations.front_link( front_work_pool, front_transmission_pool, front_utility_pool) back = implementations.back_link( servicer, back_work_pool, back_transmission_pool, back_utility_pool, default_timeout, _MAXIMUM_TIMEOUT) front.join_rear_link(link) link.join_fore_link(front) back.join_fore_link(link) link.join_rear_link(back) return _LinkedPair(front, back, pools) ././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_e0000644000175000017500000003722712600663151034533 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A test to verify an implementation of the Face layer of RPC Framework.""" import abc import contextlib import threading import unittest from grpc.framework.face import exceptions from grpc.framework.foundation import future from grpc.framework.foundation import logging_pool from grpc_test.framework.common import test_constants from grpc_test.framework.face.testing import control from grpc_test.framework.face.testing import coverage from grpc_test.framework.face.testing import digest from grpc_test.framework.face.testing import stock_service from grpc_test.framework.face.testing import test_case _MAXIMUM_POOL_SIZE = 10 class _PauseableIterator(object): def __init__(self, upstream): self._upstream = upstream self._condition = threading.Condition() self._paused = False @contextlib.contextmanager def pause(self): with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() def __iter__(self): return self def next(self): with self._condition: while self._paused: self._condition.wait() return next(self._upstream) class FutureInvocationAsynchronousEventServiceTestCase( test_case.FaceTestCase, coverage.FullCoverage): """A test of the Face layer of RPC Framework. Concrete subclasses must also extend unittest.TestCase. """ __metaclass__ = abc.ABCMeta def setUp(self): """See unittest.TestCase.setUp for full specification. Overriding implementations must call this implementation. """ self.control = control.PauseFailControl() self.digest_pool = logging_pool.pool(_MAXIMUM_POOL_SIZE) self.digest = digest.digest( stock_service.STOCK_TEST_SERVICE, self.control, self.digest_pool) self.stub, self.memo = self.set_up_implementation( self.digest.name, self.digest.methods, self.digest.event_method_implementations, None) def tearDown(self): """See unittest.TestCase.tearDown for full specification. Overriding implementations must call this implementation. """ self.tear_down_implementation(self.memo) self.digest_pool.shutdown(wait=True) def testSuccessfulUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response_future = self.stub.future_value_in_value_out( name, request, test_constants.SHORT_TIMEOUT) response = response_future.result() test_messages.verify(request, response, self) def testSuccessfulUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.SHORT_TIMEOUT) responses = list(response_iterator) test_messages.verify(request, responses, self) def testSuccessfulStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) # Use of a paused iterator of requests allows us to test that control is # returned to calling code before the iterator yields any requests. with request_iterator.pause(): response_future = self.stub.future_stream_in_value_out( name, request_iterator, test_constants.SHORT_TIMEOUT) response = response_future.result() test_messages.verify(requests, response, self) def testSuccessfulStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() request_iterator = _PauseableIterator(iter(requests)) # Use of a paused iterator of requests allows us to test that control is # returned to calling code before the iterator yields any requests. with request_iterator.pause(): response_iterator = self.stub.inline_stream_in_stream_out( name, request_iterator, test_constants.SHORT_TIMEOUT) responses = list(response_iterator) test_messages.verify(requests, responses, self) def testSequentialInvocations(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() first_response_future = self.stub.future_value_in_value_out( name, first_request, test_constants.SHORT_TIMEOUT) first_response = first_response_future.result() test_messages.verify(first_request, first_response, self) second_response_future = self.stub.future_value_in_value_out( name, second_request, test_constants.SHORT_TIMEOUT) second_response = second_response_future.result() test_messages.verify(second_request, second_response, self) def testExpiredUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.pause(): multi_callable = self.stub.unary_unary_multi_callable(name) response_future = multi_callable.future(request, test_constants.SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) with self.assertRaises(exceptions.ExpirationError): response_future.result() def testExpiredUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.pause(): response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.pause(): multi_callable = self.stub.stream_unary_multi_callable(name) response_future = multi_callable.future(iter(requests), test_constants.SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) with self.assertRaises(exceptions.ExpirationError): response_future.result() def testExpiredStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.pause(): response_iterator = self.stub.inline_stream_in_stream_out( name, iter(requests), test_constants.SHORT_TIMEOUT) with self.assertRaises(exceptions.ExpirationError): list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.fail(): response_future = self.stub.future_value_in_value_out( name, request, test_constants.SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is # indistinguishable from simply not having called its # response_callback before the expiration of the RPC. self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) with self.assertRaises(exceptions.ExpirationError): response_future.result() def testFailedUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is indistinguishable # from simply not having called its response_consumer before the # expiration of the RPC. with self.control.fail(), self.assertRaises(exceptions.ExpirationError): response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.fail(): response_future = self.stub.future_stream_in_value_out( name, iter(requests), test_constants.SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is # indistinguishable from simply not having called its # response_callback before the expiration of the RPC. self.assertIsInstance( response_future.exception(), exceptions.ExpirationError) with self.assertRaises(exceptions.ExpirationError): response_future.result() def testFailedStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is indistinguishable # from simply not having called its response_consumer before the # expiration of the RPC. with self.control.fail(), self.assertRaises(exceptions.ExpirationError): response_iterator = self.stub.inline_stream_in_stream_out( name, iter(requests), test_constants.SHORT_TIMEOUT) list(response_iterator) def testParallelInvocations(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: first_request = test_messages.request() second_request = test_messages.request() # TODO(bug 2039): use LONG_TIMEOUT instead first_response_future = self.stub.future_value_in_value_out( name, first_request, test_constants.SHORT_TIMEOUT) second_response_future = self.stub.future_value_in_value_out( name, second_request, test_constants.SHORT_TIMEOUT) first_response = first_response_future.result() second_response = second_response_future.result() test_messages.verify(first_request, first_response, self) test_messages.verify(second_request, second_response, self) @unittest.skip('TODO(nathaniel): implement.') def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() def testCancelledUnaryRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.unary_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.pause(): response_future = self.stub.future_value_in_value_out( name, request, test_constants.SHORT_TIMEOUT) cancel_method_return_value = response_future.cancel() self.assertFalse(cancel_method_return_value) self.assertTrue(response_future.cancelled()) def testCancelledUnaryRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.unary_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: request = test_messages.request() with self.control.pause(): response_iterator = self.stub.inline_value_in_stream_out( name, request, test_constants.SHORT_TIMEOUT) response_iterator.cancel() with self.assertRaises(future.CancelledError): next(response_iterator) def testCancelledStreamRequestUnaryResponse(self): for name, test_messages_sequence in ( self.digest.stream_unary_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.pause(): response_future = self.stub.future_stream_in_value_out( name, iter(requests), test_constants.SHORT_TIMEOUT) cancel_method_return_value = response_future.cancel() self.assertFalse(cancel_method_return_value) self.assertTrue(response_future.cancelled()) def testCancelledStreamRequestStreamResponse(self): for name, test_messages_sequence in ( self.digest.stream_stream_messages_sequences.iteritems()): for test_messages in test_messages_sequence: requests = test_messages.requests() with self.control.pause(): response_iterator = self.stub.inline_stream_in_stream_out( name, iter(requests), test_constants.SHORT_TIMEOUT) response_iterator.cancel() with self.assertRaises(future.CancelledError): next(response_iterator) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py0000644000175000017500000000763212600663151030070 0ustar apollockapollock# 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. """Governs coverage for the tests of the Face layer of RPC Framework.""" import abc # These classes are only valid when inherited by unittest.TestCases. # pylint: disable=invalid-name class BlockingCoverage(object): """Specification of test coverage for blocking behaviors.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def testSuccessfulUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testSuccessfulUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testSuccessfulStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testSuccessfulStreamRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testSequentialInvocations(self): raise NotImplementedError() @abc.abstractmethod def testExpiredUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredStreamRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedStreamRequestStreamResponse(self): raise NotImplementedError() class FullCoverage(BlockingCoverage): """Specification of test coverage for non-blocking behaviors.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def testParallelInvocations(self): raise NotImplementedError() @abc.abstractmethod def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() @abc.abstractmethod def testCancelledUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testCancelledUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testCancelledStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testCancelledStreamRequestStreamResponse(self): raise NotImplementedError() ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/event_invocation_synchronous_event_service_test.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/event_invocation_synchronous_event_servi0000644000175000017500000000371512600663151034624 0ustar apollockapollock# 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. """One of the tests of the Face layer of RPC Framework.""" import unittest from grpc_test.framework.face import _test_case from grpc_test.framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case class EventInvocationSynchronousEventServiceTest( _test_case.FaceTestCase, test_case.EventInvocationSynchronousEventServiceTestCase, unittest.TestCase): pass if __name__ == '__main__': unittest.main(verbosity=2) ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/future_invocation_asynchronous_event_service_test.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/future_invocation_asynchronous_event_ser0000644000175000017500000000372312600663151034616 0ustar apollockapollock# 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. """One of the tests of the Face layer of RPC Framework.""" import unittest from grpc_test.framework.face import _test_case from grpc_test.framework.face.testing import future_invocation_asynchronous_event_service_test_case as test_case class FutureInvocationAsynchronousEventServiceTest( _test_case.FaceTestCase, test_case.FutureInvocationAsynchronousEventServiceTestCase, unittest.TestCase): pass if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/__init__.py0000644000175000017500000000277212600663151026357 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/face/_test_case.py0000644000175000017500000000521412600663151026723 0ustar apollockapollock# 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. """Common lifecycle code for in-memory-ticket-exchange Face-layer tests.""" from grpc.framework.face import implementations from grpc.framework.foundation import logging_pool from grpc_test.framework.face.testing import base_util from grpc_test.framework.face.testing import test_case _TIMEOUT = 3 _MAXIMUM_POOL_SIZE = 10 class FaceTestCase(test_case.FaceTestCase): """Provides abstract Face-layer tests an in-memory implementation.""" def set_up_implementation( self, name, methods, method_implementations, multi_method_implementation): servicer_pool = logging_pool.pool(_MAXIMUM_POOL_SIZE) stub_pool = logging_pool.pool(_MAXIMUM_POOL_SIZE) servicer = implementations.servicer( servicer_pool, method_implementations, multi_method_implementation) linked_pair = base_util.linked_pair(servicer, _TIMEOUT) stub = implementations.generic_stub(linked_pair.front, stub_pool) return stub, (servicer_pool, stub_pool, linked_pair) def tear_down_implementation(self, memo): servicer_pool, stub_pool, linked_pair = memo linked_pair.shut_down() stub_pool.shutdown(wait=True) servicer_pool.shutdown(wait=True) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/common/0000755000175000017500000000000012600663151024630 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/common/test_control.py0000644000175000017500000000634712600663151027733 0ustar apollockapollock# 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. """Code for instructing systems under test to block or fail.""" import abc import contextlib import threading class Defect(Exception): """Simulates a programming defect raised into in a system under test. Use of a standard exception type is too easily misconstrued as an actual defect in either the test infrastructure or the system under test. """ class Control(object): """An object that accepts program control from a system under test. Systems under test passed a Control should call its control() method frequently during execution. The control() method may block, raise an exception, or do nothing, all according to the enclosing test's desire for the system under test to simulate hanging, failing, or functioning. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod def control(self): """Potentially does anything.""" raise NotImplementedError() class PauseFailControl(Control): """A Control that can be used to pause or fail code under control.""" def __init__(self): self._condition = threading.Condition() self._paused = False self._fail = False def control(self): with self._condition: if self._fail: raise Defect() while self._paused: self._condition.wait() @contextlib.contextmanager def pause(self): """Pauses code under control while controlling code is in context.""" with self._condition: self._paused = True yield with self._condition: self._paused = False self._condition.notify_all() @contextlib.contextmanager def fail(self): """Fails code under control while controlling code is in context.""" with self._condition: self._fail = True yield with self._condition: self._fail = False grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/common/test_constants.py0000644000175000017500000000456112600663151030263 0ustar apollockapollock# 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. """Constants shared among tests throughout RPC Framework.""" # Value for maximum duration in seconds that a test is allowed for its actual # behavioral logic, excluding all time spent deliberately waiting in the test. TIME_ALLOWANCE = 10 # Value for maximum duration in seconds of RPCs that may time out as part of a # test. SHORT_TIMEOUT = 4 # Absurdly large value for maximum duration in seconds for should-not-time-out # RPCs made during tests. LONG_TIMEOUT = 3000 # Values to supply on construction of an object that will service RPCs; these # should not be used as the actual timeout values of any RPCs made during tests. DEFAULT_TIMEOUT = 300 MAXIMUM_TIMEOUT = 3600 # The number of payloads to transmit in streaming tests. STREAM_LENGTH = 200 # The size of payloads to transmit in tests. PAYLOAD_SIZE = 256 * 1024 + 17 # The size of thread pools to use in tests. POOL_SIZE = 10 grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/common/__init__.py0000644000175000017500000000277212600663151026751 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/common/test_coverage.py0000644000175000017500000000733712600663151030046 0ustar apollockapollock# 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. """Governs coverage for tests of RPCs throughout RPC Framework.""" import abc # This code is designed for use with the unittest module. # pylint: disable=invalid-name class Coverage(object): """Specification of test coverage.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def testSuccessfulUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testSuccessfulUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testSuccessfulStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testSuccessfulStreamRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testSequentialInvocations(self): raise NotImplementedError() @abc.abstractmethod def testParallelInvocations(self): raise NotImplementedError() @abc.abstractmethod def testWaitingForSomeButNotAllParallelInvocations(self): raise NotImplementedError() @abc.abstractmethod def testCancelledUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testCancelledUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testCancelledStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testCancelledStreamRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testExpiredStreamRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedUnaryRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedUnaryRequestStreamResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedStreamRequestUnaryResponse(self): raise NotImplementedError() @abc.abstractmethod def testFailedStreamRequestStreamResponse(self): raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/__init__.py0000644000175000017500000000277212600663151025461 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/foundation/0000755000175000017500000000000012600663151025506 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py0000644000175000017500000001175612600663151030377 0ustar apollockapollock# 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. """Tests of the later module.""" import threading import time import unittest from grpc.framework.foundation import later TICK = 0.1 class LaterTest(unittest.TestCase): def test_simple_delay(self): lock = threading.Lock() cell = [0] return_value = object() def computation(): with lock: cell[0] += 1 return return_value computation_future = later.later(TICK * 2, computation) self.assertFalse(computation_future.done()) self.assertFalse(computation_future.cancelled()) time.sleep(TICK) self.assertFalse(computation_future.done()) self.assertFalse(computation_future.cancelled()) with lock: self.assertEqual(0, cell[0]) time.sleep(TICK * 2) self.assertTrue(computation_future.done()) self.assertFalse(computation_future.cancelled()) with lock: self.assertEqual(1, cell[0]) self.assertEqual(return_value, computation_future.result()) def test_callback(self): lock = threading.Lock() cell = [0] callback_called = [False] future_passed_to_callback = [None] def computation(): with lock: cell[0] += 1 computation_future = later.later(TICK * 2, computation) def callback(outcome): with lock: callback_called[0] = True future_passed_to_callback[0] = outcome computation_future.add_done_callback(callback) time.sleep(TICK) with lock: self.assertFalse(callback_called[0]) time.sleep(TICK * 2) with lock: self.assertTrue(callback_called[0]) self.assertTrue(future_passed_to_callback[0].done()) callback_called[0] = False future_passed_to_callback[0] = None computation_future.add_done_callback(callback) with lock: self.assertTrue(callback_called[0]) self.assertTrue(future_passed_to_callback[0].done()) def test_cancel(self): lock = threading.Lock() cell = [0] callback_called = [False] future_passed_to_callback = [None] def computation(): with lock: cell[0] += 1 computation_future = later.later(TICK * 2, computation) def callback(outcome): with lock: callback_called[0] = True future_passed_to_callback[0] = outcome computation_future.add_done_callback(callback) time.sleep(TICK) with lock: self.assertFalse(callback_called[0]) computation_future.cancel() self.assertTrue(computation_future.cancelled()) self.assertFalse(computation_future.running()) self.assertTrue(computation_future.done()) with lock: self.assertTrue(callback_called[0]) self.assertTrue(future_passed_to_callback[0].cancelled()) def test_result(self): lock = threading.Lock() cell = [0] callback_called = [False] future_passed_to_callback_cell = [None] return_value = object() def computation(): with lock: cell[0] += 1 return return_value computation_future = later.later(TICK * 2, computation) def callback(future_passed_to_callback): with lock: callback_called[0] = True future_passed_to_callback_cell[0] = future_passed_to_callback computation_future.add_done_callback(callback) returned_value = computation_future.result() self.assertEqual(return_value, returned_value) # The callback may not yet have been called! Sleep a tick. time.sleep(TICK) with lock: self.assertTrue(callback_called[0]) self.assertEqual(return_value, future_passed_to_callback_cell[0].result()) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py0000644000175000017500000000535612600663151031121 0ustar apollockapollock# 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. """Utilities for testing stream-related code.""" from grpc.framework.foundation import stream class TestConsumer(stream.Consumer): """A stream.Consumer instrumented for testing. Attributes: calls: A sequence of value-termination pairs describing the history of calls made on this object. """ def __init__(self): self.calls = [] def consume(self, value): """See stream.Consumer.consume for specification.""" self.calls.append((value, False)) def terminate(self): """See stream.Consumer.terminate for specification.""" self.calls.append((None, True)) def consume_and_terminate(self, value): """See stream.Consumer.consume_and_terminate for specification.""" self.calls.append((value, True)) def is_legal(self): """Reports whether or not a legal sequence of calls has been made.""" terminated = False for value, terminal in self.calls: if terminated: return False elif terminal: terminated = True elif value is None: return False else: # pylint: disable=useless-else-on-loop return True def values(self): """Returns the sequence of values that have been passed to this Consumer.""" return [value for value, _ in self.calls if value] grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/foundation/__init__.py0000644000175000017500000000277212600663151027627 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py0000644000175000017500000000443112600663151031737 0ustar apollockapollock# 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. """Tests for grpc.framework.foundation.logging_pool.""" import unittest from grpc.framework.foundation import logging_pool _POOL_SIZE = 16 class LoggingPoolTest(unittest.TestCase): def testUpAndDown(self): pool = logging_pool.pool(_POOL_SIZE) pool.shutdown(wait=True) with logging_pool.pool(_POOL_SIZE) as pool: self.assertIsNotNone(pool) def testTaskExecuted(self): test_list = [] with logging_pool.pool(_POOL_SIZE) as pool: pool.submit(lambda: test_list.append(object())).result() self.assertTrue(test_list) def testException(self): with logging_pool.pool(_POOL_SIZE) as pool: raised_exception = pool.submit(lambda: 1/0).exception() self.assertIsNotNone(raised_exception) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/base/0000755000175000017500000000000012600663151024252 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/framework/base/interfaces_test_case.py0000644000175000017500000002672112600663151031011 0ustar apollockapollock# 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. """Abstract tests against the interfaces of the base layer of RPC Framework.""" import threading import time from grpc.framework.base import interfaces from grpc.framework.base import util from grpc.framework.foundation import stream from grpc.framework.foundation import stream_util from grpc_test.framework.foundation import stream_testing TICK = 0.1 SMALL_TIMEOUT = TICK * 50 STREAM_LENGTH = 100 SYNCHRONOUS_ECHO = 'synchronous echo' ASYNCHRONOUS_ECHO = 'asynchronous echo' IMMEDIATE_FAILURE = 'immediate failure' TRIGGERED_FAILURE = 'triggered failure' WAIT_ON_CONDITION = 'wait on condition' EMPTY_OUTCOME_DICT = { interfaces.Outcome.COMPLETED: 0, interfaces.Outcome.CANCELLED: 0, interfaces.Outcome.EXPIRED: 0, interfaces.Outcome.RECEPTION_FAILURE: 0, interfaces.Outcome.TRANSMISSION_FAILURE: 0, interfaces.Outcome.SERVICER_FAILURE: 0, interfaces.Outcome.SERVICED_FAILURE: 0, } def _synchronous_echo(output_consumer): return stream_util.TransformingConsumer(lambda x: x, output_consumer) class AsynchronousEcho(stream.Consumer): """A stream.Consumer that echoes its input to another stream.Consumer.""" def __init__(self, output_consumer, pool): self._lock = threading.Lock() self._output_consumer = output_consumer self._pool = pool self._queue = [] self._spinning = False def _spin(self, value, complete): while True: if value: if complete: self._output_consumer.consume_and_terminate(value) else: self._output_consumer.consume(value) elif complete: self._output_consumer.terminate() with self._lock: if self._queue: value, complete = self._queue.pop(0) else: self._spinning = False return def consume(self, value): with self._lock: if self._spinning: self._queue.append((value, False)) else: self._spinning = True self._pool.submit(self._spin, value, False) def terminate(self): with self._lock: if self._spinning: self._queue.append((None, True)) else: self._spinning = True self._pool.submit(self._spin, None, True) def consume_and_terminate(self, value): with self._lock: if self._spinning: self._queue.append((value, True)) else: self._spinning = True self._pool.submit(self._spin, value, True) class TestServicer(interfaces.Servicer): """An interfaces.Servicer with instrumented for testing.""" def __init__(self, pool): self._pool = pool self.condition = threading.Condition() self._released = False def service(self, name, context, output_consumer): if name == SYNCHRONOUS_ECHO: return _synchronous_echo(output_consumer) elif name == ASYNCHRONOUS_ECHO: return AsynchronousEcho(output_consumer, self._pool) elif name == IMMEDIATE_FAILURE: raise ValueError() elif name == TRIGGERED_FAILURE: raise NotImplementedError elif name == WAIT_ON_CONDITION: with self.condition: while not self._released: self.condition.wait() return _synchronous_echo(output_consumer) else: raise NotImplementedError() def release(self): with self.condition: self._released = True self.condition.notify_all() class EasyServicedIngestor(interfaces.ServicedIngestor): """A trivial implementation of interfaces.ServicedIngestor.""" def __init__(self, consumer): self._consumer = consumer def consumer(self, operation_context): """See interfaces.ServicedIngestor.consumer for specification.""" return self._consumer class FrontAndBackTest(object): """A test suite usable against any joined Front and Back.""" # Pylint doesn't know that this is a unittest.TestCase mix-in. # pylint: disable=invalid-name def testSimplestCall(self): """Tests the absolute simplest call - a one-ticket fire-and-forget.""" self.front.operate( SYNCHRONOUS_ECHO, None, True, SMALL_TIMEOUT, util.none_serviced_subscription(), 'test trace ID') util.wait_for_idle(self.front) self.assertEqual( 1, self.front.operation_stats()[interfaces.Outcome.COMPLETED]) # Assuming nothing really pathological (such as pauses on the order of # SMALL_TIMEOUT interfering with this test) there are a two different ways # the back could have experienced execution up to this point: # (1) The ticket is still either in the front waiting to be transmitted # or is somewhere on the link between the front and the back. The back has # no idea that this test is even happening. Calling wait_for_idle on it # would do no good because in this case the back is idle and the call would # return with the ticket bound for it still in the front or on the link. back_operation_stats = self.back.operation_stats() first_back_possibility = EMPTY_OUTCOME_DICT # (2) The ticket arrived at the back and the back completed the operation. second_back_possibility = dict(EMPTY_OUTCOME_DICT) second_back_possibility[interfaces.Outcome.COMPLETED] = 1 self.assertIn( back_operation_stats, (first_back_possibility, second_back_possibility)) # It's true that if the ticket had arrived at the back and the back had # begun processing that wait_for_idle could hold test execution until the # back completed the operation, but that doesn't really collapse the # possibility space down to one solution. def testEntireEcho(self): """Tests a very simple one-ticket-each-way round-trip.""" test_payload = 'test payload' test_consumer = stream_testing.TestConsumer() subscription = util.full_serviced_subscription( EasyServicedIngestor(test_consumer)) self.front.operate( ASYNCHRONOUS_ECHO, test_payload, True, SMALL_TIMEOUT, subscription, 'test trace ID') util.wait_for_idle(self.front) util.wait_for_idle(self.back) self.assertEqual( 1, self.front.operation_stats()[interfaces.Outcome.COMPLETED]) self.assertEqual( 1, self.back.operation_stats()[interfaces.Outcome.COMPLETED]) self.assertListEqual([(test_payload, True)], test_consumer.calls) def testBidirectionalStreamingEcho(self): """Tests sending multiple tickets each way.""" test_payload_template = 'test_payload: %03d' test_payloads = [test_payload_template % i for i in range(STREAM_LENGTH)] test_consumer = stream_testing.TestConsumer() subscription = util.full_serviced_subscription( EasyServicedIngestor(test_consumer)) operation = self.front.operate( SYNCHRONOUS_ECHO, None, False, SMALL_TIMEOUT, subscription, 'test trace ID') for test_payload in test_payloads: operation.consumer.consume(test_payload) operation.consumer.terminate() util.wait_for_idle(self.front) util.wait_for_idle(self.back) self.assertEqual( 1, self.front.operation_stats()[interfaces.Outcome.COMPLETED]) self.assertEqual( 1, self.back.operation_stats()[interfaces.Outcome.COMPLETED]) self.assertListEqual(test_payloads, test_consumer.values()) def testCancellation(self): """Tests cancelling a long-lived operation.""" test_consumer = stream_testing.TestConsumer() subscription = util.full_serviced_subscription( EasyServicedIngestor(test_consumer)) operation = self.front.operate( ASYNCHRONOUS_ECHO, None, False, SMALL_TIMEOUT, subscription, 'test trace ID') operation.cancel() util.wait_for_idle(self.front) self.assertEqual( 1, self.front.operation_stats()[interfaces.Outcome.CANCELLED]) util.wait_for_idle(self.back) self.assertListEqual([], test_consumer.calls) # Assuming nothing really pathological (such as pauses on the order of # SMALL_TIMEOUT interfering with this test) there are a two different ways # the back could have experienced execution up to this point: # (1) Both tickets are still either in the front waiting to be transmitted # or are somewhere on the link between the front and the back. The back has # no idea that this test is even happening. Calling wait_for_idle on it # would do no good because in this case the back is idle and the call would # return with the tickets bound for it still in the front or on the link. back_operation_stats = self.back.operation_stats() first_back_possibility = EMPTY_OUTCOME_DICT # (2) Both tickets arrived within SMALL_TIMEOUT of one another at the back. # The back started processing based on the first ticket and then stopped # upon receiving the cancellation ticket. second_back_possibility = dict(EMPTY_OUTCOME_DICT) second_back_possibility[interfaces.Outcome.CANCELLED] = 1 self.assertIn( back_operation_stats, (first_back_possibility, second_back_possibility)) def testExpiration(self): """Tests that operations time out.""" timeout = TICK * 2 allowance = TICK # How much extra time to condition = threading.Condition() test_payload = 'test payload' subscription = util.termination_only_serviced_subscription() start_time = time.time() outcome_cell = [None] termination_time_cell = [None] def termination_action(outcome): with condition: outcome_cell[0] = outcome termination_time_cell[0] = time.time() condition.notify() with condition: operation = self.front.operate( SYNCHRONOUS_ECHO, test_payload, False, timeout, subscription, 'test trace ID') operation.context.add_termination_callback(termination_action) while outcome_cell[0] is None: condition.wait() duration = termination_time_cell[0] - start_time self.assertLessEqual(timeout, duration) self.assertLess(duration, timeout + allowance) self.assertEqual(interfaces.Outcome.EXPIRED, outcome_cell[0]) util.wait_for_idle(self.front) self.assertEqual( 1, self.front.operation_stats()[interfaces.Outcome.EXPIRED]) util.wait_for_idle(self.back) self.assertLessEqual( 1, self.back.operation_stats()[interfaces.Outcome.EXPIRED]) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/base/__init__.py0000644000175000017500000000277212600663151026373 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/base/implementations_test.py0000644000175000017500000000666712600663151031112 0ustar apollockapollock# 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. """Tests for grpc.framework.base.implementations.""" import unittest from grpc.framework.base import implementations from grpc.framework.base import util from grpc.framework.foundation import logging_pool from grpc_test.framework.base import interfaces_test_case POOL_MAX_WORKERS = 10 DEFAULT_TIMEOUT = 30 MAXIMUM_TIMEOUT = 60 class ImplementationsTest( interfaces_test_case.FrontAndBackTest, unittest.TestCase): def setUp(self): self.memory_transmission_pool = logging_pool.pool(POOL_MAX_WORKERS) self.front_work_pool = logging_pool.pool(POOL_MAX_WORKERS) self.front_transmission_pool = logging_pool.pool(POOL_MAX_WORKERS) self.front_utility_pool = logging_pool.pool(POOL_MAX_WORKERS) self.back_work_pool = logging_pool.pool(POOL_MAX_WORKERS) self.back_transmission_pool = logging_pool.pool(POOL_MAX_WORKERS) self.back_utility_pool = logging_pool.pool(POOL_MAX_WORKERS) self.test_pool = logging_pool.pool(POOL_MAX_WORKERS) self.test_servicer = interfaces_test_case.TestServicer(self.test_pool) self.front = implementations.front_link( self.front_work_pool, self.front_transmission_pool, self.front_utility_pool) self.back = implementations.back_link( self.test_servicer, self.back_work_pool, self.back_transmission_pool, self.back_utility_pool, DEFAULT_TIMEOUT, MAXIMUM_TIMEOUT) self.front.join_rear_link(self.back) self.back.join_fore_link(self.front) def tearDown(self): util.wait_for_idle(self.back) util.wait_for_idle(self.front) self.memory_transmission_pool.shutdown(wait=True) self.front_work_pool.shutdown(wait=True) self.front_transmission_pool.shutdown(wait=True) self.front_utility_pool.shutdown(wait=True) self.back_work_pool.shutdown(wait=True) self.back_transmission_pool.shutdown(wait=True) self.back_utility_pool.shutdown(wait=True) self.test_pool.shutdown(wait=True) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py0000644000175000017500000001050712600663151033314 0ustar apollockapollock# 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. """Tests Face interface compliance of the crust-over-core stack.""" import collections import unittest from grpc.framework.core import implementations as core_implementations from grpc.framework.crust import implementations as crust_implementations from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.links import utilities from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.face import test_cases from grpc_test.framework.interfaces.face import test_interfaces from grpc_test.framework.interfaces.links import test_utilities class _Implementation(test_interfaces.Implementation): def instantiate( self, methods, method_implementations, multi_method_implementation): pool = logging_pool.pool(test_constants.POOL_SIZE) servicer = crust_implementations.servicer( method_implementations, multi_method_implementation, pool) service_end_link = core_implementations.service_end_link( servicer, test_constants.DEFAULT_TIMEOUT, test_constants.MAXIMUM_TIMEOUT) invocation_end_link = core_implementations.invocation_end_link() invocation_end_link.join_link(service_end_link) service_end_link.join_link(invocation_end_link) service_end_link.start() invocation_end_link.start() generic_stub = crust_implementations.generic_stub(invocation_end_link, pool) # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. group = next(iter(methods))[0] # TODO(nathaniel): Add a "cardinalities_by_group" attribute to # _digest.TestServiceDigest. cardinalities = { method: method_object.cardinality() for (group, method), method_object in methods.iteritems()} dynamic_stub = crust_implementations.dynamic_stub( invocation_end_link, group, cardinalities, pool) return generic_stub, {group: dynamic_stub}, ( invocation_end_link, service_end_link, pool) def destantiate(self, memo): invocation_end_link, service_end_link, pool = memo invocation_end_link.stop(0).wait() service_end_link.stop(0).wait() invocation_end_link.join_link(utilities.NULL_LINK) service_end_link.join_link(utilities.NULL_LINK) pool.shutdown(wait=True) def invocation_metadata(self): return object() def initial_metadata(self): return object() def terminal_metadata(self): return object() def code(self): return object() def details(self): return object() def metadata_transmitted(self, original_metadata, transmitted_metadata): return original_metadata is transmitted_metadata def load_tests(loader, tests, pattern): return unittest.TestSuite( tests=tuple( loader.loadTestsFromTestCase(test_case_class) for test_case_class in test_cases.test_cases(_Implementation()))) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_links/0000755000175000017500000000000012600663151022622 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py0000644000175000017500000001757312600663151026561 0ustar apollockapollock# 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. """Test scenarios using protocol buffers.""" import abc import threading from grpc_test._junkdrawer import math_pb2 from grpc_test.framework.common import test_constants class ProtoScenario(object): """An RPC test scenario using protocol buffers.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def group_and_method(self): """Access the test group and method. Returns: The test group and method as a pair. """ raise NotImplementedError() @abc.abstractmethod def serialize_request(self, request): """Serialize a request protocol buffer. Args: request: A request protocol buffer. Returns: The bytestring serialization of the given request protocol buffer. """ raise NotImplementedError() @abc.abstractmethod def deserialize_request(self, request_bytestring): """Deserialize a request protocol buffer. Args: request_bytestring: The bytestring serialization of a request protocol buffer. Returns: The request protocol buffer deserialized from the given byte string. """ raise NotImplementedError() @abc.abstractmethod def serialize_response(self, response): """Serialize a response protocol buffer. Args: response: A response protocol buffer. Returns: The bytestring serialization of the given response protocol buffer. """ raise NotImplementedError() @abc.abstractmethod def deserialize_response(self, response_bytestring): """Deserialize a response protocol buffer. Args: response_bytestring: The bytestring serialization of a response protocol buffer. Returns: The response protocol buffer deserialized from the given byte string. """ raise NotImplementedError() @abc.abstractmethod def requests(self): """Access the sequence of requests for this scenario. Returns: A sequence of request protocol buffers. """ raise NotImplementedError() @abc.abstractmethod def response_for_request(self, request): """Access the response for a particular request. Args: request: A request protocol buffer. Returns: The response protocol buffer appropriate for the given request. """ raise NotImplementedError() @abc.abstractmethod def verify_requests(self, experimental_requests): """Verify the requests transmitted through the system under test. Args: experimental_requests: The request protocol buffers transmitted through the system under test. Returns: True if the requests satisfy this test scenario; False otherwise. """ raise NotImplementedError() @abc.abstractmethod def verify_responses(self, experimental_responses): """Verify the responses transmitted through the system under test. Args: experimental_responses: The response protocol buffers transmitted through the system under test. Returns: True if the responses satisfy this test scenario; False otherwise. """ raise NotImplementedError() class EmptyScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" def group_and_method(self): return 'math.Math', 'DivMany' def serialize_request(self, request): raise ValueError('This should not be necessary to call!') def deserialize_request(self, request_bytestring): raise ValueError('This should not be necessary to call!') def serialize_response(self, response): raise ValueError('This should not be necessary to call!') def deserialize_response(self, response_bytestring): raise ValueError('This should not be necessary to call!') def requests(self): return () def response_for_request(self, request): raise ValueError('This should not be necessary to call!') def verify_requests(self, experimental_requests): return not experimental_requests def verify_responses(self, experimental_responses): return not experimental_responses class BidirectionallyUnaryScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" _DIVIDEND = 59 _DIVISOR = 7 _QUOTIENT = 8 _REMAINDER = 3 _REQUEST = math_pb2.DivArgs(dividend=_DIVIDEND, divisor=_DIVISOR) _RESPONSE = math_pb2.DivReply(quotient=_QUOTIENT, remainder=_REMAINDER) def group_and_method(self): return 'math.Math', 'Div' def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, request_bytestring): return math_pb2.DivArgs.FromString(request_bytestring) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, response_bytestring): return math_pb2.DivReply.FromString(response_bytestring) def requests(self): return [self._REQUEST] def response_for_request(self, request): return self._RESPONSE def verify_requests(self, experimental_requests): return tuple(experimental_requests) == (self._REQUEST,) def verify_responses(self, experimental_responses): return tuple(experimental_responses) == (self._RESPONSE,) class BidirectionallyStreamingScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" _REQUESTS = tuple( math_pb2.DivArgs(dividend=59 + index, divisor=7 + index) for index in range(test_constants.STREAM_LENGTH)) def __init__(self): self._lock = threading.Lock() self._responses = [] def group_and_method(self): return 'math.Math', 'DivMany' def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, request_bytestring): return math_pb2.DivArgs.FromString(request_bytestring) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, response_bytestring): return math_pb2.DivReply.FromString(response_bytestring) def requests(self): return self._REQUESTS def response_for_request(self, request): quotient, remainder = divmod(request.dividend, request.divisor) response = math_pb2.DivReply(quotient=quotient, remainder=remainder) with self._lock: self._responses.append(response) return response def verify_requests(self, experimental_requests): return tuple(experimental_requests) == self._REQUESTS def verify_responses(self, experimental_responses): with self._lock: return tuple(experimental_responses) == tuple(self._responses) grpc-0.11.1/src/python/grpcio_test/grpc_test/_links/__init__.py0000644000175000017500000000277212600663151024743 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/_links/_transmission_test.py0000644000175000017500000002377612600663151027142 0ustar apollockapollock# 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. """Tests transmission of tickets across gRPC-on-the-wire.""" import unittest from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc._links import service from grpc.beta import interfaces as beta_interfaces from grpc.framework.interfaces.links import links from grpc_test import test_common from grpc_test._links import _proto_scenarios from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.links import test_cases from grpc_test.framework.interfaces.links import test_utilities _IDENTITY = lambda x: x class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase): def create_transmitting_links(self): service_link = service.service_link( {self.group_and_method(): self.deserialize_request}, {self.group_and_method(): self.serialize_response}) port = service_link.add_port('[::]:0', None) service_link.start() channel = _intermediary_low.Channel('localhost:%d' % port, None) invocation_link = invocation.invocation_link( channel, 'localhost', None, {self.group_and_method(): self.serialize_request}, {self.group_and_method(): self.deserialize_response}) invocation_link.start() return invocation_link, service_link def destroy_transmitting_links(self, invocation_side_link, service_side_link): invocation_side_link.stop() service_side_link.begin_stop() service_side_link.end_stop() def create_invocation_initial_metadata(self): return ( ('first_invocation_initial_metadata_key', 'just a string value'), ('second_invocation_initial_metadata_key', '0123456789'), ('third_invocation_initial_metadata_key-bin', '\x00\x57' * 100), ) def create_invocation_terminal_metadata(self): return None def create_service_initial_metadata(self): return ( ('first_service_initial_metadata_key', 'just another string value'), ('second_service_initial_metadata_key', '9876543210'), ('third_service_initial_metadata_key-bin', '\x00\x59\x02' * 100), ) def create_service_terminal_metadata(self): return ( ('first_service_terminal_metadata_key', 'yet another string value'), ('second_service_terminal_metadata_key', 'abcdefghij'), ('third_service_terminal_metadata_key-bin', '\x00\x37' * 100), ) def create_invocation_completion(self): return None, None def create_service_completion(self): return ( beta_interfaces.StatusCode.OK, b'An exuberant test "details" message!') def assertMetadataTransmitted(self, original_metadata, transmitted_metadata): self.assertTrue( test_common.metadata_transmitted( original_metadata, transmitted_metadata), '%s erroneously transmitted as %s' % ( original_metadata, transmitted_metadata)) class RoundTripTest(unittest.TestCase): def testZeroMessageRoundTrip(self): test_operation_id = object() test_group = 'test package.Test Group' test_method = 'test method' identity_transformation = {(test_group, test_method): _IDENTITY} test_code = beta_interfaces.StatusCode.OK test_message = 'a test message' service_link = service.service_link( identity_transformation, identity_transformation) service_mate = test_utilities.RecordingLink() service_link.join_link(service_mate) port = service_link.add_port('[::]:0', None) service_link.start() channel = _intermediary_low.Channel('localhost:%d' % port, None) invocation_link = invocation.invocation_link( channel, None, None, identity_transformation, identity_transformation) invocation_mate = test_utilities.RecordingLink() invocation_link.join_link(invocation_mate) invocation_link.start() invocation_ticket = links.Ticket( test_operation_id, 0, test_group, test_method, links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None, None, None, None, None, links.Ticket.Termination.COMPLETION, None) invocation_link.accept_ticket(invocation_ticket) service_mate.block_until_tickets_satisfy(test_cases.terminated) service_ticket = links.Ticket( service_mate.tickets()[-1].operation_id, 0, None, None, None, None, None, None, None, None, test_code, test_message, links.Ticket.Termination.COMPLETION, None) service_link.accept_ticket(service_ticket) invocation_mate.block_until_tickets_satisfy(test_cases.terminated) invocation_link.stop() service_link.begin_stop() service_link.end_stop() self.assertIs( service_mate.tickets()[-1].termination, links.Ticket.Termination.COMPLETION) self.assertIs( invocation_mate.tickets()[-1].termination, links.Ticket.Termination.COMPLETION) self.assertIs(invocation_mate.tickets()[-1].code, test_code) self.assertEqual(invocation_mate.tickets()[-1].message, test_message) def _perform_scenario_test(self, scenario): test_operation_id = object() test_group, test_method = scenario.group_and_method() test_code = beta_interfaces.StatusCode.OK test_message = 'a scenario test message' service_link = service.service_link( {(test_group, test_method): scenario.deserialize_request}, {(test_group, test_method): scenario.serialize_response}) service_mate = test_utilities.RecordingLink() service_link.join_link(service_mate) port = service_link.add_port('[::]:0', None) service_link.start() channel = _intermediary_low.Channel('localhost:%d' % port, None) invocation_link = invocation.invocation_link( channel, 'localhost', None, {(test_group, test_method): scenario.serialize_request}, {(test_group, test_method): scenario.deserialize_response}) invocation_mate = test_utilities.RecordingLink() invocation_link.join_link(invocation_mate) invocation_link.start() invocation_ticket = links.Ticket( test_operation_id, 0, test_group, test_method, links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None, None, None, None, None, None, None) invocation_link.accept_ticket(invocation_ticket) requests = scenario.requests() for request_index, request in enumerate(requests): request_ticket = links.Ticket( test_operation_id, 1 + request_index, None, None, None, None, 1, None, request, None, None, None, None, None) invocation_link.accept_ticket(request_ticket) service_mate.block_until_tickets_satisfy( test_cases.at_least_n_payloads_received_predicate(1 + request_index)) response_ticket = links.Ticket( service_mate.tickets()[0].operation_id, request_index, None, None, None, None, 1, None, scenario.response_for_request(request), None, None, None, None, None) service_link.accept_ticket(response_ticket) invocation_mate.block_until_tickets_satisfy( test_cases.at_least_n_payloads_received_predicate(1 + request_index)) request_count = len(requests) invocation_completion_ticket = links.Ticket( test_operation_id, request_count + 1, None, None, None, None, None, None, None, None, None, None, links.Ticket.Termination.COMPLETION, None) invocation_link.accept_ticket(invocation_completion_ticket) service_mate.block_until_tickets_satisfy(test_cases.terminated) service_completion_ticket = links.Ticket( service_mate.tickets()[0].operation_id, request_count, None, None, None, None, None, None, None, None, test_code, test_message, links.Ticket.Termination.COMPLETION, None) service_link.accept_ticket(service_completion_ticket) invocation_mate.block_until_tickets_satisfy(test_cases.terminated) invocation_link.stop() service_link.begin_stop() service_link.end_stop() observed_requests = tuple( ticket.payload for ticket in service_mate.tickets() if ticket.payload is not None) observed_responses = tuple( ticket.payload for ticket in invocation_mate.tickets() if ticket.payload is not None) self.assertTrue(scenario.verify_requests(observed_requests)) self.assertTrue(scenario.verify_responses(observed_responses)) def testEmptyScenario(self): self._perform_scenario_test(_proto_scenarios.EmptyScenario()) def testBidirectionallyUnaryScenario(self): self._perform_scenario_test(_proto_scenarios.BidirectionallyUnaryScenario()) def testBidirectionallyStreamingScenario(self): self._perform_scenario_test( _proto_scenarios.BidirectionallyStreamingScenario()) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py0000644000175000017500000000673212600663151031152 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A test of invocation-side code unconnected to an RPC server.""" import unittest from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc.framework.interfaces.links import links from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.links import test_cases from grpc_test.framework.interfaces.links import test_utilities _NULL_BEHAVIOR = lambda unused_argument: None class LonelyInvocationLinkTest(unittest.TestCase): def testUpAndDown(self): channel = _intermediary_low.Channel('nonexistent:54321', None) invocation_link = invocation.invocation_link( channel, 'nonexistent', None, {}, {}) invocation_link.start() invocation_link.stop() def _test_lonely_invocation_with_termination(self, termination): test_operation_id = object() test_group = 'test package.Test Service' test_method = 'test method' invocation_link_mate = test_utilities.RecordingLink() channel = _intermediary_low.Channel('nonexistent:54321', None) invocation_link = invocation.invocation_link( channel, 'nonexistent', None, {}, {}) invocation_link.join_link(invocation_link_mate) invocation_link.start() ticket = links.Ticket( test_operation_id, 0, test_group, test_method, links.Ticket.Subscription.FULL, test_constants.SHORT_TIMEOUT, 1, None, None, None, None, None, termination, None) invocation_link.accept_ticket(ticket) invocation_link_mate.block_until_tickets_satisfy(test_cases.terminated) invocation_link.stop() self.assertIsNot( invocation_link_mate.tickets()[-1].termination, links.Ticket.Termination.COMPLETION) def testLonelyInvocationLinkWithCommencementTicket(self): self._test_lonely_invocation_with_termination(None) def testLonelyInvocationLinkWithEntireTicket(self): self._test_lonely_invocation_with_termination( links.Ticket.Termination.COMPLETION) if __name__ == '__main__': unittest.main() grpc-0.11.1/src/python/grpcio_test/grpc_test/__init__.py0000644000175000017500000000277212600663151023464 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/0000755000175000017500000000000012600663151023122 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_links_test.py0000644000175000017500000002540312600663151026016 0ustar apollockapollock# 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. """Test of the GRPC-backed ForeLink and RearLink.""" import threading import unittest from grpc._adapter import fore from grpc._adapter import rear from grpc.framework.base import interfaces from grpc.framework.foundation import logging_pool from grpc_test._adapter import _proto_scenarios from grpc_test._adapter import _test_links _IDENTITY = lambda x: x _TIMEOUT = 32 # TODO(nathaniel): End-to-end metadata testing. def _transform_metadata(unused_metadata): return ( ('one_unused_key', 'one unused value'), ('another_unused_key', 'another unused value'), ) class RoundTripTest(unittest.TestCase): def setUp(self): self.fore_link_pool = logging_pool.pool(8) self.rear_link_pool = logging_pool.pool(8) def tearDown(self): self.rear_link_pool.shutdown(wait=True) self.fore_link_pool.shutdown(wait=True) def testZeroMessageRoundTrip(self): test_operation_id = object() test_method = 'test method' test_fore_link = _test_links.ForeLink(None, None) def rear_action(front_to_back_ticket, fore_link): if front_to_back_ticket.kind in ( interfaces.FrontToBackTicket.Kind.COMPLETION, interfaces.FrontToBackTicket.Kind.ENTIRE): back_to_front_ticket = interfaces.BackToFrontTicket( front_to_back_ticket.operation_id, 0, interfaces.BackToFrontTicket.Kind.COMPLETION, None) fore_link.accept_back_to_front_ticket(back_to_front_ticket) test_rear_link = _test_links.RearLink(rear_action, None) fore_link = fore.ForeLink( self.fore_link_pool, {test_method: None}, {test_method: None}, None, ()) fore_link.join_rear_link(test_rear_link) test_rear_link.join_fore_link(fore_link) fore_link.start() port = fore_link.port() rear_link = rear.RearLink( 'localhost', port, self.rear_link_pool, {test_method: None}, {test_method: None}, False, None, None, None, metadata_transformer=_transform_metadata) rear_link.join_fore_link(test_fore_link) test_fore_link.join_rear_link(rear_link) rear_link.start() front_to_back_ticket = interfaces.FrontToBackTicket( test_operation_id, 0, interfaces.FrontToBackTicket.Kind.ENTIRE, test_method, interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT) rear_link.accept_front_to_back_ticket(front_to_back_ticket) with test_fore_link.condition: while (not test_fore_link.tickets or test_fore_link.tickets[-1].kind is interfaces.BackToFrontTicket.Kind.CONTINUATION): test_fore_link.condition.wait() rear_link.stop() fore_link.stop() with test_fore_link.condition: self.assertIs( test_fore_link.tickets[-1].kind, interfaces.BackToFrontTicket.Kind.COMPLETION) def testEntireRoundTrip(self): test_operation_id = object() test_method = 'test method' test_front_to_back_datum = b'\x07' test_back_to_front_datum = b'\x08' test_fore_link = _test_links.ForeLink(None, None) rear_sequence_number = [0] def rear_action(front_to_back_ticket, fore_link): if front_to_back_ticket.payload is None: payload = None else: payload = test_back_to_front_datum terminal = front_to_back_ticket.kind in ( interfaces.FrontToBackTicket.Kind.COMPLETION, interfaces.FrontToBackTicket.Kind.ENTIRE) if payload is not None or terminal: if terminal: kind = interfaces.BackToFrontTicket.Kind.COMPLETION else: kind = interfaces.BackToFrontTicket.Kind.CONTINUATION back_to_front_ticket = interfaces.BackToFrontTicket( front_to_back_ticket.operation_id, rear_sequence_number[0], kind, payload) rear_sequence_number[0] += 1 fore_link.accept_back_to_front_ticket(back_to_front_ticket) test_rear_link = _test_links.RearLink(rear_action, None) fore_link = fore.ForeLink( self.fore_link_pool, {test_method: _IDENTITY}, {test_method: _IDENTITY}, None, ()) fore_link.join_rear_link(test_rear_link) test_rear_link.join_fore_link(fore_link) fore_link.start() port = fore_link.port() rear_link = rear.RearLink( 'localhost', port, self.rear_link_pool, {test_method: _IDENTITY}, {test_method: _IDENTITY}, False, None, None, None) rear_link.join_fore_link(test_fore_link) test_fore_link.join_rear_link(rear_link) rear_link.start() front_to_back_ticket = interfaces.FrontToBackTicket( test_operation_id, 0, interfaces.FrontToBackTicket.Kind.ENTIRE, test_method, interfaces.ServicedSubscription.Kind.FULL, None, test_front_to_back_datum, _TIMEOUT) rear_link.accept_front_to_back_ticket(front_to_back_ticket) with test_fore_link.condition: while (not test_fore_link.tickets or test_fore_link.tickets[-1].kind is not interfaces.BackToFrontTicket.Kind.COMPLETION): test_fore_link.condition.wait() rear_link.stop() fore_link.stop() with test_rear_link.condition: front_to_back_payloads = tuple( ticket.payload for ticket in test_rear_link.tickets if ticket.payload is not None) with test_fore_link.condition: back_to_front_payloads = tuple( ticket.payload for ticket in test_fore_link.tickets if ticket.payload is not None) self.assertTupleEqual((test_front_to_back_datum,), front_to_back_payloads) self.assertTupleEqual((test_back_to_front_datum,), back_to_front_payloads) def _perform_scenario_test(self, scenario): test_operation_id = object() test_method = scenario.method() test_fore_link = _test_links.ForeLink(None, None) rear_lock = threading.Lock() rear_sequence_number = [0] def rear_action(front_to_back_ticket, fore_link): with rear_lock: if front_to_back_ticket.payload is not None: response = scenario.response_for_request(front_to_back_ticket.payload) else: response = None terminal = front_to_back_ticket.kind in ( interfaces.FrontToBackTicket.Kind.COMPLETION, interfaces.FrontToBackTicket.Kind.ENTIRE) if response is not None or terminal: if terminal: kind = interfaces.BackToFrontTicket.Kind.COMPLETION else: kind = interfaces.BackToFrontTicket.Kind.CONTINUATION back_to_front_ticket = interfaces.BackToFrontTicket( front_to_back_ticket.operation_id, rear_sequence_number[0], kind, response) rear_sequence_number[0] += 1 fore_link.accept_back_to_front_ticket(back_to_front_ticket) test_rear_link = _test_links.RearLink(rear_action, None) fore_link = fore.ForeLink( self.fore_link_pool, {test_method: scenario.deserialize_request}, {test_method: scenario.serialize_response}, None, ()) fore_link.join_rear_link(test_rear_link) test_rear_link.join_fore_link(fore_link) fore_link.start() port = fore_link.port() rear_link = rear.RearLink( 'localhost', port, self.rear_link_pool, {test_method: scenario.serialize_request}, {test_method: scenario.deserialize_response}, False, None, None, None) rear_link.join_fore_link(test_fore_link) test_fore_link.join_rear_link(rear_link) rear_link.start() commencement_ticket = interfaces.FrontToBackTicket( test_operation_id, 0, interfaces.FrontToBackTicket.Kind.COMMENCEMENT, test_method, interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT) fore_sequence_number = 1 rear_link.accept_front_to_back_ticket(commencement_ticket) for request in scenario.requests(): continuation_ticket = interfaces.FrontToBackTicket( test_operation_id, fore_sequence_number, interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None, None, request, None) fore_sequence_number += 1 rear_link.accept_front_to_back_ticket(continuation_ticket) completion_ticket = interfaces.FrontToBackTicket( test_operation_id, fore_sequence_number, interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None, None, None) fore_sequence_number += 1 rear_link.accept_front_to_back_ticket(completion_ticket) with test_fore_link.condition: while (not test_fore_link.tickets or test_fore_link.tickets[-1].kind is not interfaces.BackToFrontTicket.Kind.COMPLETION): test_fore_link.condition.wait() rear_link.stop() fore_link.stop() with test_rear_link.condition: requests = tuple( ticket.payload for ticket in test_rear_link.tickets if ticket.payload is not None) with test_fore_link.condition: responses = tuple( ticket.payload for ticket in test_fore_link.tickets if ticket.payload is not None) self.assertTrue(scenario.verify_requests(requests)) self.assertTrue(scenario.verify_responses(responses)) def testEmptyScenario(self): self._perform_scenario_test(_proto_scenarios.EmptyScenario()) def testBidirectionallyUnaryScenario(self): self._perform_scenario_test(_proto_scenarios.BidirectionallyUnaryScenario()) def testBidirectionallyStreamingScenario(self): self._perform_scenario_test( _proto_scenarios.BidirectionallyStreamingScenario()) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_c_test.py0000644000175000017500000000403112600663151025112 0ustar apollockapollock# 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. import time import unittest from grpc._adapter import _c from grpc._adapter import _types class CTypeSmokeTest(unittest.TestCase): def testCompletionQueueUpDown(self): completion_queue = _c.CompletionQueue() del completion_queue def testServerUpDown(self): completion_queue = _c.CompletionQueue() serv = _c.Server(completion_queue, []) del serv del completion_queue def testChannelUpDown(self): channel = _c.Channel('[::]:0', []) del channel if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_test_links.py0000644000175000017500000000545612600663151026024 0ustar apollockapollock# 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. """Links suitable for use in tests.""" import threading from grpc.framework.base import interfaces class ForeLink(interfaces.ForeLink): """A ForeLink suitable for use in tests of RearLinks.""" def __init__(self, action, rear_link): self.condition = threading.Condition() self.tickets = [] self.action = action self.rear_link = rear_link def accept_back_to_front_ticket(self, ticket): with self.condition: self.tickets.append(ticket) self.condition.notify_all() action, rear_link = self.action, self.rear_link if action is not None: action(ticket, rear_link) def join_rear_link(self, rear_link): with self.condition: self.rear_link = rear_link class RearLink(interfaces.RearLink): """A RearLink suitable for use in tests of ForeLinks.""" def __init__(self, action, fore_link): self.condition = threading.Condition() self.tickets = [] self.action = action self.fore_link = fore_link def accept_front_to_back_ticket(self, ticket): with self.condition: self.tickets.append(ticket) self.condition.notify_all() action, fore_link = self.action, self.fore_link if action is not None: action(ticket, fore_link) def join_fore_link(self, fore_link): with self.condition: self.fore_link = fore_link grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py0000644000175000017500000001735312600663151027055 0ustar apollockapollock# 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. """Test scenarios using protocol buffers.""" import abc import threading from grpc_test._junkdrawer import math_pb2 class ProtoScenario(object): """An RPC test scenario using protocol buffers.""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def method(self): """Access the test method name. Returns: The test method name. """ raise NotImplementedError() @abc.abstractmethod def serialize_request(self, request): """Serialize a request protocol buffer. Args: request: A request protocol buffer. Returns: The bytestring serialization of the given request protocol buffer. """ raise NotImplementedError() @abc.abstractmethod def deserialize_request(self, request_bytestring): """Deserialize a request protocol buffer. Args: request_bytestring: The bytestring serialization of a request protocol buffer. Returns: The request protocol buffer deserialized from the given byte string. """ raise NotImplementedError() @abc.abstractmethod def serialize_response(self, response): """Serialize a response protocol buffer. Args: response: A response protocol buffer. Returns: The bytestring serialization of the given response protocol buffer. """ raise NotImplementedError() @abc.abstractmethod def deserialize_response(self, response_bytestring): """Deserialize a response protocol buffer. Args: response_bytestring: The bytestring serialization of a response protocol buffer. Returns: The response protocol buffer deserialized from the given byte string. """ raise NotImplementedError() @abc.abstractmethod def requests(self): """Access the sequence of requests for this scenario. Returns: A sequence of request protocol buffers. """ raise NotImplementedError() @abc.abstractmethod def response_for_request(self, request): """Access the response for a particular request. Args: request: A request protocol buffer. Returns: The response protocol buffer appropriate for the given request. """ raise NotImplementedError() @abc.abstractmethod def verify_requests(self, experimental_requests): """Verify the requests transmitted through the system under test. Args: experimental_requests: The request protocol buffers transmitted through the system under test. Returns: True if the requests satisfy this test scenario; False otherwise. """ raise NotImplementedError() @abc.abstractmethod def verify_responses(self, experimental_responses): """Verify the responses transmitted through the system under test. Args: experimental_responses: The response protocol buffers transmitted through the system under test. Returns: True if the responses satisfy this test scenario; False otherwise. """ raise NotImplementedError() class EmptyScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" def method(self): return 'DivMany' def serialize_request(self, request): raise ValueError('This should not be necessary to call!') def deserialize_request(self, request_bytestring): raise ValueError('This should not be necessary to call!') def serialize_response(self, response): raise ValueError('This should not be necessary to call!') def deserialize_response(self, response_bytestring): raise ValueError('This should not be necessary to call!') def requests(self): return () def response_for_request(self, request): raise ValueError('This should not be necessary to call!') def verify_requests(self, experimental_requests): return not experimental_requests def verify_responses(self, experimental_responses): return not experimental_responses class BidirectionallyUnaryScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" _DIVIDEND = 59 _DIVISOR = 7 _QUOTIENT = 8 _REMAINDER = 3 _REQUEST = math_pb2.DivArgs(dividend=_DIVIDEND, divisor=_DIVISOR) _RESPONSE = math_pb2.DivReply(quotient=_QUOTIENT, remainder=_REMAINDER) def method(self): return 'Div' def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, request_bytestring): return math_pb2.DivArgs.FromString(request_bytestring) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, response_bytestring): return math_pb2.DivReply.FromString(response_bytestring) def requests(self): return [self._REQUEST] def response_for_request(self, request): return self._RESPONSE def verify_requests(self, experimental_requests): return tuple(experimental_requests) == (self._REQUEST,) def verify_responses(self, experimental_responses): return tuple(experimental_responses) == (self._RESPONSE,) class BidirectionallyStreamingScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" _STREAM_LENGTH = 200 _REQUESTS = tuple( math_pb2.DivArgs(dividend=59 + index, divisor=7 + index) for index in range(_STREAM_LENGTH)) def __init__(self): self._lock = threading.Lock() self._responses = [] def method(self): return 'DivMany' def serialize_request(self, request): return request.SerializeToString() def deserialize_request(self, request_bytestring): return math_pb2.DivArgs.FromString(request_bytestring) def serialize_response(self, response): return response.SerializeToString() def deserialize_response(self, response_bytestring): return math_pb2.DivReply.FromString(response_bytestring) def requests(self): return self._REQUESTS def response_for_request(self, request): quotient, remainder = divmod(request.dividend, request.divisor) response = math_pb2.DivReply(quotient=quotient, remainder=remainder) with self._lock: self._responses.append(response) return response def verify_requests(self, experimental_requests): return tuple(experimental_requests) == self._REQUESTS def verify_responses(self, experimental_responses): with self._lock: return tuple(experimental_responses) == tuple(self._responses) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_lonely_rear_link_test.py0000644000175000017500000000704612600663151030231 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A test of invocation-side code unconnected to an RPC server.""" import unittest from grpc._adapter import rear from grpc.framework.base import interfaces from grpc.framework.foundation import logging_pool from grpc_test._adapter import _test_links _IDENTITY = lambda x: x _TIMEOUT = 2 class LonelyRearLinkTest(unittest.TestCase): def setUp(self): self.pool = logging_pool.pool(8) def tearDown(self): self.pool.shutdown(wait=True) def testUpAndDown(self): rear_link = rear.RearLink( 'nonexistent', 54321, self.pool, {}, {}, False, None, None, None) rear_link.start() rear_link.stop() def _perform_lonely_client_test_with_ticket_kind( self, front_to_back_ticket_kind): test_operation_id = object() test_method = 'test method' fore_link = _test_links.ForeLink(None, None) rear_link = rear.RearLink( 'nonexistent', 54321, self.pool, {test_method: None}, {test_method: None}, False, None, None, None) rear_link.join_fore_link(fore_link) rear_link.start() front_to_back_ticket = interfaces.FrontToBackTicket( test_operation_id, 0, front_to_back_ticket_kind, test_method, interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT) rear_link.accept_front_to_back_ticket(front_to_back_ticket) with fore_link.condition: while True: if (fore_link.tickets and fore_link.tickets[-1].kind is not interfaces.BackToFrontTicket.Kind.CONTINUATION): break fore_link.condition.wait() rear_link.stop() with fore_link.condition: self.assertIsNot( fore_link.tickets[-1].kind, interfaces.BackToFrontTicket.Kind.COMPLETION) def testLonelyClientCommencementTicket(self): self._perform_lonely_client_test_with_ticket_kind( interfaces.FrontToBackTicket.Kind.COMMENCEMENT) def testLonelyClientEntireTicket(self): self._perform_lonely_client_test_with_ticket_kind( interfaces.FrontToBackTicket.Kind.ENTIRE) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_low_test.py0000644000175000017500000003056312600663151025502 0ustar apollockapollock# 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. import threading import time import unittest from grpc import _grpcio_metadata from grpc._adapter import _types from grpc._adapter import _low def wait_for_events(completion_queues, deadline): """ Args: completion_queues: list of completion queues to wait for events on deadline: absolute deadline to wait until Returns: a sequence of events of length len(completion_queues). """ results = [None] * len(completion_queues) lock = threading.Lock() threads = [] def set_ith_result(i, completion_queue): result = completion_queue.next(deadline) with lock: results[i] = result for i, completion_queue in enumerate(completion_queues): thread = threading.Thread(target=set_ith_result, args=[i, completion_queue]) thread.start() threads.append(thread) for thread in threads: thread.join() return results class InsecureServerInsecureClient(unittest.TestCase): def setUp(self): self.server_completion_queue = _low.CompletionQueue() self.server = _low.Server(self.server_completion_queue, []) self.port = self.server.add_http2_port('[::]:0') self.client_completion_queue = _low.CompletionQueue() self.client_channel = _low.Channel('localhost:%d'%self.port, []) self.server.start() def tearDown(self): self.server.shutdown() del self.client_channel self.client_completion_queue.shutdown() while (self.client_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN): pass self.server_completion_queue.shutdown() while (self.server_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN): pass del self.client_completion_queue del self.server_completion_queue del self.server def testEcho(self): deadline = time.time() + 5 event_time_tolerance = 2 deadline_tolerance = 0.25 client_metadata_ascii_key = 'key' client_metadata_ascii_value = 'val' client_metadata_bin_key = 'key-bin' client_metadata_bin_value = b'\0'*1000 server_initial_metadata_key = 'init_me_me_me' server_initial_metadata_value = 'whodawha?' server_trailing_metadata_key = 'california_is_in_a_drought' server_trailing_metadata_value = 'zomg it is' server_status_code = _types.StatusCode.OK server_status_details = 'our work is never over' request = 'blarghaflargh' response = 'his name is robert paulson' method = 'twinkies' host = 'hostess' server_request_tag = object() request_call_result = self.server.request_call(self.server_completion_queue, server_request_tag) self.assertEqual(_types.CallError.OK, request_call_result) client_call_tag = object() client_call = self.client_channel.create_call( self.client_completion_queue, method, host, deadline) client_initial_metadata = [ (client_metadata_ascii_key, client_metadata_ascii_value), (client_metadata_bin_key, client_metadata_bin_value) ] client_start_batch_result = client_call.start_batch([ _types.OpArgs.send_initial_metadata(client_initial_metadata), _types.OpArgs.send_message(request, 0), _types.OpArgs.send_close_from_client(), _types.OpArgs.recv_initial_metadata(), _types.OpArgs.recv_message(), _types.OpArgs.recv_status_on_client() ], client_call_tag) self.assertEqual(_types.CallError.OK, client_start_batch_result) client_no_event, request_event, = wait_for_events( [self.client_completion_queue, self.server_completion_queue], time.time() + event_time_tolerance) self.assertEqual(client_no_event, None) self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type) self.assertIsInstance(request_event.call, _low.Call) self.assertIs(server_request_tag, request_event.tag) self.assertEqual(1, len(request_event.results)) received_initial_metadata = dict(request_event.results[0].initial_metadata) # Check that our metadata were transmitted self.assertEqual( dict(client_initial_metadata), dict((x, received_initial_metadata[x]) for x in zip(*client_initial_metadata)[0])) # Check that Python's user agent string is a part of the full user agent # string self.assertIn('Python-gRPC-{}'.format(_grpcio_metadata.__version__), received_initial_metadata['user-agent']) self.assertEqual(method, request_event.call_details.method) self.assertEqual(host, request_event.call_details.host) self.assertLess(abs(deadline - request_event.call_details.deadline), deadline_tolerance) # Check that the channel is connected, and that both it and the call have # the proper target and peer; do this after the first flurry of messages to # avoid the possibility that connection was delayed by the core until the # first message was sent. self.assertEqual(_types.ConnectivityState.READY, self.client_channel.check_connectivity_state(False)) self.assertIsNotNone(self.client_channel.target()) self.assertIsNotNone(client_call.peer()) server_call_tag = object() server_call = request_event.call server_initial_metadata = [ (server_initial_metadata_key, server_initial_metadata_value) ] server_trailing_metadata = [ (server_trailing_metadata_key, server_trailing_metadata_value) ] server_start_batch_result = server_call.start_batch([ _types.OpArgs.send_initial_metadata(server_initial_metadata), _types.OpArgs.recv_message(), _types.OpArgs.send_message(response, 0), _types.OpArgs.recv_close_on_server(), _types.OpArgs.send_status_from_server( server_trailing_metadata, server_status_code, server_status_details) ], server_call_tag) self.assertEqual(_types.CallError.OK, server_start_batch_result) client_event, server_event, = wait_for_events( [self.client_completion_queue, self.server_completion_queue], time.time() + event_time_tolerance) self.assertEqual(6, len(client_event.results)) found_client_op_types = set() for client_result in client_event.results: # we expect each op type to be unique self.assertNotIn(client_result.type, found_client_op_types) found_client_op_types.add(client_result.type) if client_result.type == _types.OpType.RECV_INITIAL_METADATA: self.assertEqual(dict(server_initial_metadata), dict(client_result.initial_metadata)) elif client_result.type == _types.OpType.RECV_MESSAGE: self.assertEqual(response, client_result.message) elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT: self.assertEqual(dict(server_trailing_metadata), dict(client_result.trailing_metadata)) self.assertEqual(server_status_details, client_result.status.details) self.assertEqual(server_status_code, client_result.status.code) self.assertEqual(set([ _types.OpType.SEND_INITIAL_METADATA, _types.OpType.SEND_MESSAGE, _types.OpType.SEND_CLOSE_FROM_CLIENT, _types.OpType.RECV_INITIAL_METADATA, _types.OpType.RECV_MESSAGE, _types.OpType.RECV_STATUS_ON_CLIENT ]), found_client_op_types) self.assertEqual(5, len(server_event.results)) found_server_op_types = set() for server_result in server_event.results: self.assertNotIn(client_result.type, found_server_op_types) found_server_op_types.add(server_result.type) if server_result.type == _types.OpType.RECV_MESSAGE: self.assertEqual(request, server_result.message) elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER: self.assertFalse(server_result.cancelled) self.assertEqual(set([ _types.OpType.SEND_INITIAL_METADATA, _types.OpType.RECV_MESSAGE, _types.OpType.SEND_MESSAGE, _types.OpType.RECV_CLOSE_ON_SERVER, _types.OpType.SEND_STATUS_FROM_SERVER ]), found_server_op_types) del client_call del server_call class HangingServerShutdown(unittest.TestCase): def setUp(self): self.server_completion_queue = _low.CompletionQueue() self.server = _low.Server(self.server_completion_queue, []) self.port = self.server.add_http2_port('[::]:0') self.client_completion_queue = _low.CompletionQueue() self.client_channel = _low.Channel('localhost:%d'%self.port, []) self.server.start() def tearDown(self): self.server.shutdown() del self.client_channel self.client_completion_queue.shutdown() self.server_completion_queue.shutdown() while True: client_event, server_event = wait_for_events( [self.client_completion_queue, self.server_completion_queue], float("+inf")) if (client_event.type == _types.EventType.QUEUE_SHUTDOWN and server_event.type == _types.EventType.QUEUE_SHUTDOWN): break del self.client_completion_queue del self.server_completion_queue del self.server def testHangingServerCall(self): deadline = time.time() + 5 deadline_tolerance = 0.25 event_time_tolerance = 2 cancel_all_calls_time_tolerance = 0.5 request = 'blarghaflargh' method = 'twinkies' host = 'hostess' server_request_tag = object() request_call_result = self.server.request_call(self.server_completion_queue, server_request_tag) client_call_tag = object() client_call = self.client_channel.create_call(self.client_completion_queue, method, host, deadline) client_start_batch_result = client_call.start_batch([ _types.OpArgs.send_initial_metadata([]), _types.OpArgs.send_message(request, 0), _types.OpArgs.send_close_from_client(), _types.OpArgs.recv_initial_metadata(), _types.OpArgs.recv_message(), _types.OpArgs.recv_status_on_client() ], client_call_tag) client_no_event, request_event, = wait_for_events( [self.client_completion_queue, self.server_completion_queue], time.time() + event_time_tolerance) # Now try to shutdown the server and expect that we see server shutdown # almost immediately after calling cancel_all_calls. with self.assertRaises(RuntimeError): self.server.cancel_all_calls() shutdown_tag = object() self.server.shutdown(shutdown_tag) pre_cancel_timestamp = time.time() self.server.cancel_all_calls() finish_shutdown_timestamp = None client_call_event, server_shutdown_event = wait_for_events( [self.client_completion_queue, self.server_completion_queue], time.time() + event_time_tolerance) self.assertIs(shutdown_tag, server_shutdown_event.tag) self.assertGreater(pre_cancel_timestamp + cancel_all_calls_time_tolerance, time.time()) del client_call if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_face_test_case.py0000644000175000017500000001041112600663151026560 0ustar apollockapollock# 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. """Common construction and destruction for GRPC-backed Face-layer tests.""" import unittest from grpc._adapter import fore from grpc._adapter import rear from grpc.framework.base import util from grpc.framework.base import implementations as base_implementations from grpc.framework.face import implementations as face_implementations from grpc.framework.foundation import logging_pool from grpc_test.framework.face.testing import coverage from grpc_test.framework.face.testing import serial from grpc_test.framework.face.testing import test_case _TIMEOUT = 3 _MAXIMUM_TIMEOUT = 90 _MAXIMUM_POOL_SIZE = 4 class FaceTestCase(test_case.FaceTestCase, coverage.BlockingCoverage): """Provides abstract Face-layer tests a GRPC-backed implementation.""" def set_up_implementation( self, name, methods, method_implementations, multi_method_implementation): pool = logging_pool.pool(_MAXIMUM_POOL_SIZE) servicer = face_implementations.servicer( pool, method_implementations, multi_method_implementation) serialization = serial.serialization(methods) fore_link = fore.ForeLink( pool, serialization.request_deserializers, serialization.response_serializers, None, ()) fore_link.start() port = fore_link.port() rear_link = rear.RearLink( 'localhost', port, pool, serialization.request_serializers, serialization.response_deserializers, False, None, None, None) rear_link.start() front = base_implementations.front_link(pool, pool, pool) back = base_implementations.back_link( servicer, pool, pool, pool, _TIMEOUT, _MAXIMUM_TIMEOUT) fore_link.join_rear_link(back) back.join_fore_link(fore_link) rear_link.join_fore_link(front) front.join_rear_link(rear_link) stub = face_implementations.generic_stub(front, pool) return stub, (rear_link, fore_link, front, back) def tear_down_implementation(self, memo): rear_link, fore_link, front, back = memo # TODO(nathaniel): Waiting for the front and back to idle possibly should # not be necessary - investigate as part of graceful shutdown work. util.wait_for_idle(front) util.wait_for_idle(back) rear_link.stop() fore_link.stop() @unittest.skip('Service-side failure not transmitted by GRPC.') def testFailedUnaryRequestUnaryResponse(self): raise NotImplementedError() @unittest.skip('Service-side failure not transmitted by GRPC.') def testFailedUnaryRequestStreamResponse(self): raise NotImplementedError() @unittest.skip('Service-side failure not transmitted by GRPC.') def testFailedStreamRequestUnaryResponse(self): raise NotImplementedError() @unittest.skip('Service-side failure not transmitted by GRPC.') def testFailedStreamRequestStreamResponse(self): raise NotImplementedError() grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/__init__.py0000644000175000017500000000277212600663151025243 0ustar apollockapollock# 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. ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_event_invocation_synchronous_event_service_test.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_event_invocation_synchronous_event_service_te0000644000175000017500000000372112600663151034644 0ustar apollockapollock# 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. """One of the tests of the Face layer of RPC Framework.""" import unittest from grpc_test._adapter import _face_test_case from grpc_test.framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case class EventInvocationSynchronousEventServiceTest( _face_test_case.FaceTestCase, test_case.EventInvocationSynchronousEventServiceTestCase, unittest.TestCase): pass if __name__ == '__main__': unittest.main(verbosity=2) ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootgrpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_future_invocation_asynchronous_event_service_test.pygrpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_future_invocation_asynchronous_event_service_0000644000175000017500000000372712600663151034653 0ustar apollockapollock# 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. """One of the tests of the Face layer of RPC Framework.""" import unittest from grpc_test._adapter import _face_test_case from grpc_test.framework.face.testing import future_invocation_asynchronous_event_service_test_case as test_case class FutureInvocationAsynchronousEventServiceTest( _face_test_case.FaceTestCase, test_case.FutureInvocationAsynchronousEventServiceTestCase, unittest.TestCase): pass if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_blocking_invocation_inline_service_test.py0000644000175000017500000000367312600663151034002 0ustar apollockapollock# 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. """One of the tests of the Face layer of RPC Framework.""" import unittest from grpc_test._adapter import _face_test_case from grpc_test.framework.face.testing import blocking_invocation_inline_service_test_case as test_case class BlockingInvocationInlineServiceTest( _face_test_case.FaceTestCase, test_case.BlockingInvocationInlineServiceTestCase, unittest.TestCase): pass if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py0000644000175000017500000004164312600663151030257 0ustar apollockapollock# 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. """Tests for the old '_low'.""" import Queue import threading import time import unittest from grpc._adapter import _intermediary_low as _low _STREAM_LENGTH = 300 _TIMEOUT = 5 _AFTER_DELAY = 2 _FUTURE = time.time() + 60 * 60 * 24 _BYTE_SEQUENCE = b'\abcdefghijklmnopqrstuvwxyz0123456789' * 200 _BYTE_SEQUENCE_SEQUENCE = tuple( bytes(bytearray((row + column) % 256 for column in range(row))) for row in range(_STREAM_LENGTH)) class LonelyClientTest(unittest.TestCase): def testLonelyClient(self): host = 'nosuchhostexists' port = 54321 method = 'test method' deadline = time.time() + _TIMEOUT after_deadline = deadline + _AFTER_DELAY metadata_tag = object() finish_tag = object() completion_queue = _low.CompletionQueue() channel = _low.Channel('%s:%d' % (host, port), None) client_call = _low.Call(channel, completion_queue, method, host, deadline) client_call.invoke(completion_queue, metadata_tag, finish_tag) first_event = completion_queue.get(after_deadline) self.assertIsNotNone(first_event) second_event = completion_queue.get(after_deadline) self.assertIsNotNone(second_event) kinds = [event.kind for event in (first_event, second_event)] self.assertItemsEqual( (_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH), kinds) self.assertIsNone(completion_queue.get(after_deadline)) completion_queue.stop() stop_event = completion_queue.get(_FUTURE) self.assertEqual(_low.Event.Kind.STOP, stop_event.kind) del client_call del channel del completion_queue def _drive_completion_queue(completion_queue, event_queue): while True: event = completion_queue.get(_FUTURE) if event.kind is _low.Event.Kind.STOP: break event_queue.put(event) class EchoTest(unittest.TestCase): def setUp(self): self.host = 'localhost' self.server_completion_queue = _low.CompletionQueue() self.server = _low.Server(self.server_completion_queue) port = self.server.add_http2_addr('[::]:0') self.server.start() self.server_events = Queue.Queue() self.server_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(self.server_completion_queue, self.server_events)) self.server_completion_queue_thread.start() self.client_completion_queue = _low.CompletionQueue() self.channel = _low.Channel('%s:%d' % (self.host, port), None) self.client_events = Queue.Queue() self.client_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(self.client_completion_queue, self.client_events)) self.client_completion_queue_thread.start() def tearDown(self): self.server.stop() self.server_completion_queue.stop() self.client_completion_queue.stop() self.server_completion_queue_thread.join() self.client_completion_queue_thread.join() del self.server def _perform_echo_test(self, test_data): method = 'test method' details = 'test details' server_leading_metadata_key = 'my_server_leading_key' server_leading_metadata_value = 'my_server_leading_value' server_trailing_metadata_key = 'my_server_trailing_key' server_trailing_metadata_value = 'my_server_trailing_value' client_metadata_key = 'my_client_key' client_metadata_value = 'my_client_value' server_leading_binary_metadata_key = 'my_server_leading_key-bin' server_leading_binary_metadata_value = b'\0'*2047 server_trailing_binary_metadata_key = 'my_server_trailing_key-bin' server_trailing_binary_metadata_value = b'\0'*2047 client_binary_metadata_key = 'my_client_key-bin' client_binary_metadata_value = b'\0'*2047 deadline = _FUTURE metadata_tag = object() finish_tag = object() write_tag = object() complete_tag = object() service_tag = object() read_tag = object() status_tag = object() server_data = [] client_data = [] client_call = _low.Call(self.channel, self.client_completion_queue, method, self.host, deadline) client_call.add_metadata(client_metadata_key, client_metadata_value) client_call.add_metadata(client_binary_metadata_key, client_binary_metadata_value) client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag) self.server.service(service_tag) service_accepted = self.server_events.get() self.assertIsNotNone(service_accepted) self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED) self.assertIs(service_accepted.tag, service_tag) self.assertEqual(method, service_accepted.service_acceptance.method) self.assertEqual(self.host, service_accepted.service_acceptance.host) self.assertIsNotNone(service_accepted.service_acceptance.call) metadata = dict(service_accepted.metadata) self.assertIn(client_metadata_key, metadata) self.assertEqual(client_metadata_value, metadata[client_metadata_key]) self.assertIn(client_binary_metadata_key, metadata) self.assertEqual(client_binary_metadata_value, metadata[client_binary_metadata_key]) server_call = service_accepted.service_acceptance.call server_call.accept(self.server_completion_queue, finish_tag) server_call.add_metadata(server_leading_metadata_key, server_leading_metadata_value) server_call.add_metadata(server_leading_binary_metadata_key, server_leading_binary_metadata_value) server_call.premetadata() metadata_accepted = self.client_events.get() self.assertIsNotNone(metadata_accepted) self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind) self.assertEqual(metadata_tag, metadata_accepted.tag) metadata = dict(metadata_accepted.metadata) self.assertIn(server_leading_metadata_key, metadata) self.assertEqual(server_leading_metadata_value, metadata[server_leading_metadata_key]) self.assertIn(server_leading_binary_metadata_key, metadata) self.assertEqual(server_leading_binary_metadata_value, metadata[server_leading_binary_metadata_key]) for datum in test_data: client_call.write(datum, write_tag, _low.WriteFlags.WRITE_NO_COMPRESS) write_accepted = self.client_events.get() self.assertIsNotNone(write_accepted) self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED) self.assertIs(write_accepted.tag, write_tag) self.assertIs(write_accepted.write_accepted, True) server_call.read(read_tag) read_accepted = self.server_events.get() self.assertIsNotNone(read_accepted) self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) self.assertEqual(read_tag, read_accepted.tag) self.assertIsNotNone(read_accepted.bytes) server_data.append(read_accepted.bytes) server_call.write(read_accepted.bytes, write_tag, 0) write_accepted = self.server_events.get() self.assertIsNotNone(write_accepted) self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind) self.assertEqual(write_tag, write_accepted.tag) self.assertTrue(write_accepted.write_accepted) client_call.read(read_tag) read_accepted = self.client_events.get() self.assertIsNotNone(read_accepted) self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) self.assertEqual(read_tag, read_accepted.tag) self.assertIsNotNone(read_accepted.bytes) client_data.append(read_accepted.bytes) client_call.complete(complete_tag) complete_accepted = self.client_events.get() self.assertIsNotNone(complete_accepted) self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED) self.assertIs(complete_accepted.tag, complete_tag) self.assertIs(complete_accepted.complete_accepted, True) server_call.read(read_tag) read_accepted = self.server_events.get() self.assertIsNotNone(read_accepted) self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) self.assertEqual(read_tag, read_accepted.tag) self.assertIsNone(read_accepted.bytes) server_call.add_metadata(server_trailing_metadata_key, server_trailing_metadata_value) server_call.add_metadata(server_trailing_binary_metadata_key, server_trailing_binary_metadata_value) server_call.status(_low.Status(_low.Code.OK, details), status_tag) server_terminal_event_one = self.server_events.get() server_terminal_event_two = self.server_events.get() if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED: status_accepted = server_terminal_event_one rpc_accepted = server_terminal_event_two else: status_accepted = server_terminal_event_two rpc_accepted = server_terminal_event_one self.assertIsNotNone(status_accepted) self.assertIsNotNone(rpc_accepted) self.assertEqual(_low.Event.Kind.COMPLETE_ACCEPTED, status_accepted.kind) self.assertEqual(status_tag, status_accepted.tag) self.assertTrue(status_accepted.complete_accepted) self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind) self.assertEqual(finish_tag, rpc_accepted.tag) self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status) client_call.read(read_tag) client_terminal_event_one = self.client_events.get() client_terminal_event_two = self.client_events.get() if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED: read_accepted = client_terminal_event_one finish_accepted = client_terminal_event_two else: read_accepted = client_terminal_event_two finish_accepted = client_terminal_event_one self.assertIsNotNone(read_accepted) self.assertIsNotNone(finish_accepted) self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) self.assertEqual(read_tag, read_accepted.tag) self.assertIsNone(read_accepted.bytes) self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind) self.assertEqual(finish_tag, finish_accepted.tag) self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status) metadata = dict(finish_accepted.metadata) self.assertIn(server_trailing_metadata_key, metadata) self.assertEqual(server_trailing_metadata_value, metadata[server_trailing_metadata_key]) self.assertIn(server_trailing_binary_metadata_key, metadata) self.assertEqual(server_trailing_binary_metadata_value, metadata[server_trailing_binary_metadata_key]) self.assertSetEqual(set(key for key, _ in finish_accepted.metadata), set((server_trailing_metadata_key, server_trailing_binary_metadata_key,))) server_timeout_none_event = self.server_completion_queue.get(0) self.assertIsNone(server_timeout_none_event) client_timeout_none_event = self.client_completion_queue.get(0) self.assertIsNone(client_timeout_none_event) self.assertSequenceEqual(test_data, server_data) self.assertSequenceEqual(test_data, client_data) def testNoEcho(self): self._perform_echo_test(()) def testOneByteEcho(self): self._perform_echo_test([b'\x07']) def testOneManyByteEcho(self): self._perform_echo_test([_BYTE_SEQUENCE]) def testManyOneByteEchoes(self): self._perform_echo_test(_BYTE_SEQUENCE) def testManyManyByteEchoes(self): self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE) class CancellationTest(unittest.TestCase): def setUp(self): self.host = 'localhost' self.server_completion_queue = _low.CompletionQueue() self.server = _low.Server(self.server_completion_queue) port = self.server.add_http2_addr('[::]:0') self.server.start() self.server_events = Queue.Queue() self.server_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(self.server_completion_queue, self.server_events)) self.server_completion_queue_thread.start() self.client_completion_queue = _low.CompletionQueue() self.channel = _low.Channel('%s:%d' % (self.host, port), None) self.client_events = Queue.Queue() self.client_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(self.client_completion_queue, self.client_events)) self.client_completion_queue_thread.start() def tearDown(self): self.server.stop() self.server_completion_queue.stop() self.client_completion_queue.stop() self.server_completion_queue_thread.join() self.client_completion_queue_thread.join() del self.server def testCancellation(self): method = 'test method' deadline = _FUTURE metadata_tag = object() finish_tag = object() write_tag = object() service_tag = object() read_tag = object() test_data = _BYTE_SEQUENCE_SEQUENCE server_data = [] client_data = [] client_call = _low.Call(self.channel, self.client_completion_queue, method, self.host, deadline) client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag) self.server.service(service_tag) service_accepted = self.server_events.get() server_call = service_accepted.service_acceptance.call server_call.accept(self.server_completion_queue, finish_tag) server_call.premetadata() metadata_accepted = self.client_events.get() self.assertIsNotNone(metadata_accepted) for datum in test_data: client_call.write(datum, write_tag, 0) write_accepted = self.client_events.get() server_call.read(read_tag) read_accepted = self.server_events.get() server_data.append(read_accepted.bytes) server_call.write(read_accepted.bytes, write_tag, 0) write_accepted = self.server_events.get() self.assertIsNotNone(write_accepted) client_call.read(read_tag) read_accepted = self.client_events.get() client_data.append(read_accepted.bytes) client_call.cancel() # cancel() is idempotent. client_call.cancel() client_call.cancel() client_call.cancel() server_call.read(read_tag) server_terminal_event_one = self.server_events.get() server_terminal_event_two = self.server_events.get() if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED: read_accepted = server_terminal_event_one rpc_accepted = server_terminal_event_two else: read_accepted = server_terminal_event_two rpc_accepted = server_terminal_event_one self.assertIsNotNone(read_accepted) self.assertIsNotNone(rpc_accepted) self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind) self.assertIsNone(read_accepted.bytes) self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind) self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status) finish_event = self.client_events.get() self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind) self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), finish_event.status) server_timeout_none_event = self.server_completion_queue.get(0) self.assertIsNone(server_timeout_none_event) client_timeout_none_event = self.client_completion_queue.get(0) self.assertIsNone(client_timeout_none_event) self.assertSequenceEqual(test_data, server_data) self.assertSequenceEqual(test_data, client_data) class ExpirationTest(unittest.TestCase): @unittest.skip('TODO(nathaniel): Expiration test!') def testExpiration(self): pass if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/_adapter/.gitignore0000644000175000017500000000003312600663151025106 0ustar apollockapollock*.a *.so *.dll *.pyc *.pyd grpc-0.11.1/src/python/grpcio_test/grpc_test/_junkdrawer/0000755000175000017500000000000012600663151023656 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py0000644000175000017500000002041712600663151025730 0ustar apollockapollock# 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. # TODO(nathaniel): Remove this from source control after having made # generation from the math.proto source part of GRPC's build-and-test # process. # Generated by the protocol buffer compiler. DO NOT EDIT! # source: math.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='math.proto', package='math', serialized_pb=_b('\n\nmath.proto\x12\x04math\",\n\x07\x44ivArgs\x12\x10\n\x08\x64ividend\x18\x01 \x02(\x03\x12\x0f\n\x07\x64ivisor\x18\x02 \x02(\x03\"/\n\x08\x44ivReply\x12\x10\n\x08quotient\x18\x01 \x02(\x03\x12\x11\n\tremainder\x18\x02 \x02(\x03\"\x18\n\x07\x46ibArgs\x12\r\n\x05limit\x18\x01 \x01(\x03\"\x12\n\x03Num\x12\x0b\n\x03num\x18\x01 \x02(\x03\"\x19\n\x08\x46ibReply\x12\r\n\x05\x63ount\x18\x01 \x02(\x03\x32\xa4\x01\n\x04Math\x12&\n\x03\x44iv\x12\r.math.DivArgs\x1a\x0e.math.DivReply\"\x00\x12.\n\x07\x44ivMany\x12\r.math.DivArgs\x1a\x0e.math.DivReply\"\x00(\x01\x30\x01\x12#\n\x03\x46ib\x12\r.math.FibArgs\x1a\t.math.Num\"\x00\x30\x01\x12\x1f\n\x03Sum\x12\t.math.Num\x1a\t.math.Num\"\x00(\x01') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) _DIVARGS = _descriptor.Descriptor( name='DivArgs', full_name='math.DivArgs', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='dividend', full_name='math.DivArgs.dividend', index=0, number=1, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='divisor', full_name='math.DivArgs.divisor', index=1, number=2, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=20, serialized_end=64, ) _DIVREPLY = _descriptor.Descriptor( name='DivReply', full_name='math.DivReply', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='quotient', full_name='math.DivReply.quotient', index=0, number=1, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='remainder', full_name='math.DivReply.remainder', index=1, number=2, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=66, serialized_end=113, ) _FIBARGS = _descriptor.Descriptor( name='FibArgs', full_name='math.FibArgs', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='limit', full_name='math.FibArgs.limit', index=0, number=1, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=115, serialized_end=139, ) _NUM = _descriptor.Descriptor( name='Num', full_name='math.Num', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='num', full_name='math.Num.num', index=0, number=1, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=141, serialized_end=159, ) _FIBREPLY = _descriptor.Descriptor( name='FibReply', full_name='math.FibReply', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='count', full_name='math.FibReply.count', index=0, number=1, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=161, serialized_end=186, ) DESCRIPTOR.message_types_by_name['DivArgs'] = _DIVARGS DESCRIPTOR.message_types_by_name['DivReply'] = _DIVREPLY DESCRIPTOR.message_types_by_name['FibArgs'] = _FIBARGS DESCRIPTOR.message_types_by_name['Num'] = _NUM DESCRIPTOR.message_types_by_name['FibReply'] = _FIBREPLY DivArgs = _reflection.GeneratedProtocolMessageType('DivArgs', (_message.Message,), dict( DESCRIPTOR = _DIVARGS, __module__ = 'math_pb2' # @@protoc_insertion_point(class_scope:math.DivArgs) )) _sym_db.RegisterMessage(DivArgs) DivReply = _reflection.GeneratedProtocolMessageType('DivReply', (_message.Message,), dict( DESCRIPTOR = _DIVREPLY, __module__ = 'math_pb2' # @@protoc_insertion_point(class_scope:math.DivReply) )) _sym_db.RegisterMessage(DivReply) FibArgs = _reflection.GeneratedProtocolMessageType('FibArgs', (_message.Message,), dict( DESCRIPTOR = _FIBARGS, __module__ = 'math_pb2' # @@protoc_insertion_point(class_scope:math.FibArgs) )) _sym_db.RegisterMessage(FibArgs) Num = _reflection.GeneratedProtocolMessageType('Num', (_message.Message,), dict( DESCRIPTOR = _NUM, __module__ = 'math_pb2' # @@protoc_insertion_point(class_scope:math.Num) )) _sym_db.RegisterMessage(Num) FibReply = _reflection.GeneratedProtocolMessageType('FibReply', (_message.Message,), dict( DESCRIPTOR = _FIBREPLY, __module__ = 'math_pb2' # @@protoc_insertion_point(class_scope:math.FibReply) )) _sym_db.RegisterMessage(FibReply) # @@protoc_insertion_point(module_scope) grpc-0.11.1/src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py0000644000175000017500000001315712600663151026125 0ustar apollockapollock# 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. # TODO(nathaniel): Remove this from source control after having made # generation from the stock.proto source part of GRPC's build-and-test # process. # Generated by the protocol buffer compiler. DO NOT EDIT! # source: stock.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='stock.proto', package='stock', serialized_pb=_b('\n\x0bstock.proto\x12\x05stock\">\n\x0cStockRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x1e\n\x13num_trades_to_watch\x18\x02 \x01(\x05:\x01\x30\"+\n\nStockReply\x12\r\n\x05price\x18\x01 \x01(\x02\x12\x0e\n\x06symbol\x18\x02 \x01(\t2\x96\x02\n\x05Stock\x12=\n\x11GetLastTradePrice\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00\x12I\n\x19GetLastTradePriceMultiple\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00(\x01\x30\x01\x12?\n\x11WatchFutureTrades\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00\x30\x01\x12\x42\n\x14GetHighestTradePrice\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00(\x01') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) _STOCKREQUEST = _descriptor.Descriptor( name='StockRequest', full_name='stock.StockRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='symbol', full_name='stock.StockRequest.symbol', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='num_trades_to_watch', full_name='stock.StockRequest.num_trades_to_watch', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=True, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=22, serialized_end=84, ) _STOCKREPLY = _descriptor.Descriptor( name='StockReply', full_name='stock.StockReply', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='price', full_name='stock.StockReply.price', index=0, number=1, type=2, cpp_type=6, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='symbol', full_name='stock.StockReply.symbol', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=86, serialized_end=129, ) DESCRIPTOR.message_types_by_name['StockRequest'] = _STOCKREQUEST DESCRIPTOR.message_types_by_name['StockReply'] = _STOCKREPLY StockRequest = _reflection.GeneratedProtocolMessageType('StockRequest', (_message.Message,), dict( DESCRIPTOR = _STOCKREQUEST, __module__ = 'stock_pb2' # @@protoc_insertion_point(class_scope:stock.StockRequest) )) _sym_db.RegisterMessage(StockRequest) StockReply = _reflection.GeneratedProtocolMessageType('StockReply', (_message.Message,), dict( DESCRIPTOR = _STOCKREPLY, __module__ = 'stock_pb2' # @@protoc_insertion_point(class_scope:stock.StockReply) )) _sym_db.RegisterMessage(StockReply) # @@protoc_insertion_point(module_scope) grpc-0.11.1/src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py0000644000175000017500000000277212600663151025777 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/test_common.py0000644000175000017500000000622112600663151024245 0ustar apollockapollock# 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. """Common code used throughout tests of gRPC.""" import collections INVOCATION_INITIAL_METADATA = ((b'0', b'abc'), (b'1', b'def'), (b'2', b'ghi'),) SERVICE_INITIAL_METADATA = ((b'3', b'jkl'), (b'4', b'mno'), (b'5', b'pqr'),) SERVICE_TERMINAL_METADATA = ((b'6', b'stu'), (b'7', b'vwx'), (b'8', b'yza'),) DETAILS = b'test details' def metadata_transmitted(original_metadata, transmitted_metadata): """Judges whether or not metadata was acceptably transmitted. gRPC is allowed to insert key-value pairs into the metadata values given by applications and to reorder key-value pairs with different keys but it is not allowed to alter existing key-value pairs or to reorder key-value pairs with the same key. Args: original_metadata: A metadata value used in a test of gRPC. transmitted_metadata: A metadata value corresponding to original_metadata after having been transmitted via gRPC. Returns: A boolean indicating whether transmitted_metadata accurately reflects original_metadata after having been transmitted via gRPC. """ original = collections.defaultdict(list) for key, value in original_metadata: original[key].append(value) transmitted = collections.defaultdict(list) for key, value in transmitted_metadata: transmitted[key].append(value) for key, values in original.iteritems(): transmitted_values = transmitted[key] transmitted_iterator = iter(transmitted_values) try: for value in values: while True: transmitted_value = next(transmitted_iterator) if value == transmitted_value: break except StopIteration: return False else: return True grpc-0.11.1/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py0000644000175000017500000001512512600663151033553 0ustar apollockapollock# 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. """Tests Face compliance of the crust-over-core-over-gRPC-links stack.""" import collections import unittest from grpc._adapter import _intermediary_low from grpc._links import invocation from grpc._links import service from grpc.beta import interfaces as beta_interfaces from grpc.framework.core import implementations as core_implementations from grpc.framework.crust import implementations as crust_implementations from grpc.framework.foundation import logging_pool from grpc.framework.interfaces.links import utilities from grpc_test import test_common as grpc_test_common from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.face import test_cases from grpc_test.framework.interfaces.face import test_interfaces class _SerializationBehaviors( collections.namedtuple( '_SerializationBehaviors', ('request_serializers', 'request_deserializers', 'response_serializers', 'response_deserializers',))): pass def _serialization_behaviors_from_test_methods(test_methods): request_serializers = {} request_deserializers = {} response_serializers = {} response_deserializers = {} for (group, method), test_method in test_methods.iteritems(): request_serializers[group, method] = test_method.serialize_request request_deserializers[group, method] = test_method.deserialize_request response_serializers[group, method] = test_method.serialize_response response_deserializers[group, method] = test_method.deserialize_response return _SerializationBehaviors( request_serializers, request_deserializers, response_serializers, response_deserializers) class _Implementation(test_interfaces.Implementation): def instantiate( self, methods, method_implementations, multi_method_implementation): pool = logging_pool.pool(test_constants.POOL_SIZE) servicer = crust_implementations.servicer( method_implementations, multi_method_implementation, pool) serialization_behaviors = _serialization_behaviors_from_test_methods( methods) invocation_end_link = core_implementations.invocation_end_link() service_end_link = core_implementations.service_end_link( servicer, test_constants.DEFAULT_TIMEOUT, test_constants.MAXIMUM_TIMEOUT) service_grpc_link = service.service_link( serialization_behaviors.request_deserializers, serialization_behaviors.response_serializers) port = service_grpc_link.add_port('[::]:0', None) channel = _intermediary_low.Channel('localhost:%d' % port, None) invocation_grpc_link = invocation.invocation_link( channel, b'localhost', None, serialization_behaviors.request_serializers, serialization_behaviors.response_deserializers) invocation_end_link.join_link(invocation_grpc_link) invocation_grpc_link.join_link(invocation_end_link) service_grpc_link.join_link(service_end_link) service_end_link.join_link(service_grpc_link) service_end_link.start() invocation_end_link.start() invocation_grpc_link.start() service_grpc_link.start() generic_stub = crust_implementations.generic_stub(invocation_end_link, pool) # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. group = next(iter(methods))[0] # TODO(nathaniel): Add a "cardinalities_by_group" attribute to # _digest.TestServiceDigest. cardinalities = { method: method_object.cardinality() for (group, method), method_object in methods.iteritems()} dynamic_stub = crust_implementations.dynamic_stub( invocation_end_link, group, cardinalities, pool) return generic_stub, {group: dynamic_stub}, ( invocation_end_link, invocation_grpc_link, service_grpc_link, service_end_link, pool) def destantiate(self, memo): (invocation_end_link, invocation_grpc_link, service_grpc_link, service_end_link, pool) = memo invocation_end_link.stop(0).wait() invocation_grpc_link.stop() service_grpc_link.begin_stop() service_end_link.stop(0).wait() service_grpc_link.end_stop() invocation_end_link.join_link(utilities.NULL_LINK) invocation_grpc_link.join_link(utilities.NULL_LINK) service_grpc_link.join_link(utilities.NULL_LINK) service_end_link.join_link(utilities.NULL_LINK) pool.shutdown(wait=True) def invocation_metadata(self): return grpc_test_common.INVOCATION_INITIAL_METADATA def initial_metadata(self): return grpc_test_common.SERVICE_INITIAL_METADATA def terminal_metadata(self): return grpc_test_common.SERVICE_TERMINAL_METADATA def code(self): return beta_interfaces.StatusCode.OK def details(self): return grpc_test_common.DETAILS def metadata_transmitted(self, original_metadata, transmitted_metadata): return original_metadata is None or grpc_test_common.metadata_transmitted( original_metadata, transmitted_metadata) def load_tests(loader, tests, pattern): return unittest.TestSuite( tests=tuple( loader.loadTestsFromTestCase(test_case_class) for test_case_class in test_cases.test_cases(_Implementation()))) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/0000755000175000017500000000000012600663151022256 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_test/beta/_utilities_test.py0000644000175000017500000001105212600663151026040 0ustar apollockapollock# 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. """Tests of grpc.beta.utilities.""" import threading import time import unittest from grpc._adapter import _low from grpc._adapter import _types from grpc.beta import implementations from grpc.beta import utilities from grpc.framework.foundation import future from grpc_test.framework.common import test_constants def _drive_completion_queue(completion_queue): while True: event = completion_queue.next(time.time() + 24 * 60 * 60) if event.type == _types.EventType.QUEUE_SHUTDOWN: break class _Callback(object): def __init__(self): self._condition = threading.Condition() self._value = None def accept_value(self, value): with self._condition: self._value = value self._condition.notify_all() def block_until_called(self): with self._condition: while self._value is None: self._condition.wait() return self._value class ChannelConnectivityTest(unittest.TestCase): def test_lonely_channel_connectivity(self): channel = implementations.insecure_channel('localhost', 12345) callback = _Callback() ready_future = utilities.channel_ready_future(channel) ready_future.add_done_callback(callback.accept_value) with self.assertRaises(future.TimeoutError): ready_future.result(test_constants.SHORT_TIMEOUT) self.assertFalse(ready_future.cancelled()) self.assertFalse(ready_future.done()) self.assertTrue(ready_future.running()) ready_future.cancel() value_passed_to_callback = callback.block_until_called() self.assertIs(ready_future, value_passed_to_callback) self.assertTrue(ready_future.cancelled()) self.assertTrue(ready_future.done()) self.assertFalse(ready_future.running()) def test_immediately_connectable_channel_connectivity(self): server_completion_queue = _low.CompletionQueue() server = _low.Server(server_completion_queue, []) port = server.add_http2_port('[::]:0') server.start() server_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(server_completion_queue,)) server_completion_queue_thread.start() channel = implementations.insecure_channel('localhost', port) callback = _Callback() try: ready_future = utilities.channel_ready_future(channel) ready_future.add_done_callback(callback.accept_value) self.assertIsNone( ready_future.result(test_constants.SHORT_TIMEOUT)) value_passed_to_callback = callback.block_until_called() self.assertIs(ready_future, value_passed_to_callback) self.assertFalse(ready_future.cancelled()) self.assertTrue(ready_future.done()) self.assertFalse(ready_future.running()) # Cancellation after maturity has no effect. ready_future.cancel() self.assertFalse(ready_future.cancelled()) self.assertTrue(ready_future.done()) self.assertFalse(ready_future.running()) finally: ready_future.cancel() server.shutdown() server_completion_queue.shutdown() server_completion_queue_thread.join() if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/test_utilities.py0000644000175000017500000000474712600663151025716 0ustar apollockapollock# 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. """Test-appropriate entry points into the gRPC Python Beta API.""" from grpc._adapter import _intermediary_low from grpc.beta import implementations def not_really_secure_channel( host, port, client_credentials, server_host_override): """Creates an insecure Channel to a remote host. Args: host: The name of the remote host to which to connect. port: The port of the remote host to which to connect. client_credentials: The implementations.ClientCredentials with which to connect. server_host_override: The target name used for SSL host name checking. Returns: An implementations.Channel to the remote host through which RPCs may be conducted. """ hostport = '%s:%d' % (host, port) intermediary_low_channel = _intermediary_low.Channel( hostport, client_credentials._intermediary_low_credentials, server_host_override=server_host_override) return implementations.Channel( intermediary_low_channel._internal, intermediary_low_channel) grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py0000644000175000017500000001324612600663151026752 0ustar apollockapollock# 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. """Tests Face interface compliance of the gRPC Python Beta API.""" import collections import unittest from grpc.beta import implementations from grpc.beta import interfaces from grpc_test import resources from grpc_test import test_common as grpc_test_common from grpc_test.beta import test_utilities from grpc_test.framework.common import test_constants from grpc_test.framework.interfaces.face import test_cases from grpc_test.framework.interfaces.face import test_interfaces _SERVER_HOST_OVERRIDE = 'foo.test.google.fr' class _SerializationBehaviors( collections.namedtuple( '_SerializationBehaviors', ('request_serializers', 'request_deserializers', 'response_serializers', 'response_deserializers',))): pass def _serialization_behaviors_from_test_methods(test_methods): request_serializers = {} request_deserializers = {} response_serializers = {} response_deserializers = {} for (group, method), test_method in test_methods.iteritems(): request_serializers[group, method] = test_method.serialize_request request_deserializers[group, method] = test_method.deserialize_request response_serializers[group, method] = test_method.serialize_response response_deserializers[group, method] = test_method.deserialize_response return _SerializationBehaviors( request_serializers, request_deserializers, response_serializers, response_deserializers) class _Implementation(test_interfaces.Implementation): def instantiate( self, methods, method_implementations, multi_method_implementation): serialization_behaviors = _serialization_behaviors_from_test_methods( methods) # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. service = next(iter(methods))[0] # TODO(nathaniel): Add a "cardinalities_by_group" attribute to # _digest.TestServiceDigest. cardinalities = { method: method_object.cardinality() for (group, method), method_object in methods.iteritems()} server_options = implementations.server_options( request_deserializers=serialization_behaviors.request_deserializers, response_serializers=serialization_behaviors.response_serializers, thread_pool_size=test_constants.POOL_SIZE) server = implementations.server( method_implementations, options=server_options) server_credentials = implementations.ssl_server_credentials( [(resources.private_key(), resources.certificate_chain(),),]) port = server.add_secure_port('[::]:0', server_credentials) server.start() client_credentials = implementations.ssl_client_credentials( resources.test_root_certificates(), None, None) channel = test_utilities.not_really_secure_channel( 'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE) stub_options = implementations.stub_options( request_serializers=serialization_behaviors.request_serializers, response_deserializers=serialization_behaviors.response_deserializers, thread_pool_size=test_constants.POOL_SIZE) generic_stub = implementations.generic_stub(channel, options=stub_options) dynamic_stub = implementations.dynamic_stub( channel, service, cardinalities, options=stub_options) return generic_stub, {service: dynamic_stub}, server def destantiate(self, memo): memo.stop(test_constants.SHORT_TIMEOUT).wait() def invocation_metadata(self): return grpc_test_common.INVOCATION_INITIAL_METADATA def initial_metadata(self): return grpc_test_common.SERVICE_INITIAL_METADATA def terminal_metadata(self): return grpc_test_common.SERVICE_TERMINAL_METADATA def code(self): return interfaces.StatusCode.OK def details(self): return grpc_test_common.DETAILS def metadata_transmitted(self, original_metadata, transmitted_metadata): return original_metadata is None or grpc_test_common.metadata_transmitted( original_metadata, transmitted_metadata) def load_tests(loader, tests, pattern): return unittest.TestSuite( tests=tuple( loader.loadTestsFromTestCase(test_case_class) for test_case_class in test_cases.test_cases(_Implementation()))) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/__init__.py0000644000175000017500000000277212600663151024377 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py0000644000175000017500000001733612600663151030246 0ustar apollockapollock# 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. """Tests of grpc.beta._connectivity_channel.""" import threading import time import unittest from grpc._adapter import _low from grpc._adapter import _types from grpc.beta import _connectivity_channel from grpc.beta import interfaces from grpc_test.framework.common import test_constants def _drive_completion_queue(completion_queue): while True: event = completion_queue.next(time.time() + 24 * 60 * 60) if event.type == _types.EventType.QUEUE_SHUTDOWN: break class _Callback(object): def __init__(self): self._condition = threading.Condition() self._connectivities = [] def update(self, connectivity): with self._condition: self._connectivities.append(connectivity) self._condition.notify() def connectivities(self): with self._condition: return tuple(self._connectivities) def block_until_connectivities_satisfy(self, predicate): with self._condition: while True: connectivities = tuple(self._connectivities) if predicate(connectivities): return connectivities else: self._condition.wait() class ChannelConnectivityTest(unittest.TestCase): def test_lonely_channel_connectivity(self): low_channel = _low.Channel('localhost:12345', ()) callback = _Callback() connectivity_channel = _connectivity_channel.ConnectivityChannel( low_channel) connectivity_channel.subscribe(callback.update, try_to_connect=False) first_connectivities = callback.block_until_connectivities_satisfy(bool) connectivity_channel.subscribe(callback.update, try_to_connect=True) second_connectivities = callback.block_until_connectivities_satisfy( lambda connectivities: 2 <= len(connectivities)) # Wait for a connection that will never happen. time.sleep(test_constants.SHORT_TIMEOUT) third_connectivities = callback.connectivities() connectivity_channel.unsubscribe(callback.update) fourth_connectivities = callback.connectivities() connectivity_channel.unsubscribe(callback.update) fifth_connectivities = callback.connectivities() self.assertSequenceEqual( (interfaces.ChannelConnectivity.IDLE,), first_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.READY, second_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.READY, third_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.READY, fourth_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.READY, fifth_connectivities) def test_immediately_connectable_channel_connectivity(self): server_completion_queue = _low.CompletionQueue() server = _low.Server(server_completion_queue, []) port = server.add_http2_port('[::]:0') server.start() server_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(server_completion_queue,)) server_completion_queue_thread.start() low_channel = _low.Channel('localhost:%d' % port, ()) first_callback = _Callback() second_callback = _Callback() connectivity_channel = _connectivity_channel.ConnectivityChannel( low_channel) connectivity_channel.subscribe(first_callback.update, try_to_connect=False) first_connectivities = first_callback.block_until_connectivities_satisfy( bool) # Wait for a connection that will never happen because try_to_connect=True # has not yet been passed. time.sleep(test_constants.SHORT_TIMEOUT) second_connectivities = first_callback.connectivities() connectivity_channel.subscribe(second_callback.update, try_to_connect=True) third_connectivities = first_callback.block_until_connectivities_satisfy( lambda connectivities: 2 <= len(connectivities)) fourth_connectivities = second_callback.block_until_connectivities_satisfy( bool) # Wait for a connection that will happen (or may already have happened). first_callback.block_until_connectivities_satisfy( lambda connectivities: interfaces.ChannelConnectivity.READY in connectivities) second_callback.block_until_connectivities_satisfy( lambda connectivities: interfaces.ChannelConnectivity.READY in connectivities) connectivity_channel.unsubscribe(first_callback.update) connectivity_channel.unsubscribe(second_callback.update) server.shutdown() server_completion_queue.shutdown() server_completion_queue_thread.join() self.assertSequenceEqual( (interfaces.ChannelConnectivity.IDLE,), first_connectivities) self.assertSequenceEqual( (interfaces.ChannelConnectivity.IDLE,), second_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.TRANSIENT_FAILURE, third_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.FATAL_FAILURE, third_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.TRANSIENT_FAILURE, fourth_connectivities) self.assertNotIn( interfaces.ChannelConnectivity.FATAL_FAILURE, fourth_connectivities) def test_reachable_then_unreachable_channel_connectivity(self): server_completion_queue = _low.CompletionQueue() server = _low.Server(server_completion_queue, []) port = server.add_http2_port('[::]:0') server.start() server_completion_queue_thread = threading.Thread( target=_drive_completion_queue, args=(server_completion_queue,)) server_completion_queue_thread.start() low_channel = _low.Channel('localhost:%d' % port, ()) callback = _Callback() connectivity_channel = _connectivity_channel.ConnectivityChannel( low_channel) connectivity_channel.subscribe(callback.update, try_to_connect=True) callback.block_until_connectivities_satisfy( lambda connectivities: interfaces.ChannelConnectivity.READY in connectivities) # Now take down the server and confirm that channel readiness is repudiated. server.shutdown() callback.block_until_connectivities_satisfy( lambda connectivities: connectivities[-1] is not interfaces.ChannelConnectivity.READY) connectivity_channel.unsubscribe(callback.update) server.shutdown() server_completion_queue.shutdown() server_completion_queue_thread.join() if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/_not_found_test.py0000644000175000017500000000601412600663151026022 0ustar apollockapollock# 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. """Tests of RPC-method-not-found behavior.""" import unittest from grpc.beta import implementations from grpc.beta import interfaces from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants class NotFoundTest(unittest.TestCase): def setUp(self): self._server = implementations.server({}) port = self._server.add_insecure_port('[::]:0') channel = implementations.insecure_channel('localhost', port) self._generic_stub = implementations.generic_stub(channel) self._server.start() def tearDown(self): self._server.stop(0).wait() self._generic_stub = None def test_blocking_unary_unary_not_found(self): with self.assertRaises(face.LocalError) as exception_assertion_context: self._generic_stub.blocking_unary_unary( 'groop', 'meffod', b'abc', test_constants.LONG_TIMEOUT, with_call=True) self.assertIs( exception_assertion_context.exception.code, interfaces.StatusCode.UNIMPLEMENTED) def test_future_stream_unary_not_found(self): rpc_future = self._generic_stub.future_stream_unary( 'grupe', 'mevvod', b'def', test_constants.LONG_TIMEOUT) with self.assertRaises(face.LocalError) as exception_assertion_context: rpc_future.result() self.assertIs( exception_assertion_context.exception.code, interfaces.StatusCode.UNIMPLEMENTED) self.assertIs( rpc_future.exception().code, interfaces.StatusCode.UNIMPLEMENTED) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py0000644000175000017500000002061212600663151026640 0ustar apollockapollock# 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. """Tests Face interface compliance of the gRPC Python Beta API.""" import threading import unittest from grpc.beta import implementations from grpc.beta import interfaces from grpc.framework.common import cardinality from grpc.framework.interfaces.face import utilities from grpc_test import resources from grpc_test.beta import test_utilities from grpc_test.framework.common import test_constants _SERVER_HOST_OVERRIDE = 'foo.test.google.fr' _GROUP = 'group' _UNARY_UNARY = 'unary-unary' _UNARY_STREAM = 'unary-stream' _STREAM_UNARY = 'stream-unary' _STREAM_STREAM = 'stream-stream' _REQUEST = b'abc' _RESPONSE = b'123' class _Servicer(object): def __init__(self): self._condition = threading.Condition() self._peer = None self._serviced = False def unary_unary(self, request, context): with self._condition: self._request = request self._peer = context.protocol_context().peer() context.protocol_context().disable_next_response_compression() self._serviced = True self._condition.notify_all() return _RESPONSE def unary_stream(self, request, context): with self._condition: self._request = request self._peer = context.protocol_context().peer() context.protocol_context().disable_next_response_compression() self._serviced = True self._condition.notify_all() return yield def stream_unary(self, request_iterator, context): for request in request_iterator: self._request = request with self._condition: self._peer = context.protocol_context().peer() context.protocol_context().disable_next_response_compression() self._serviced = True self._condition.notify_all() return _RESPONSE def stream_stream(self, request_iterator, context): for request in request_iterator: with self._condition: self._peer = context.protocol_context().peer() context.protocol_context().disable_next_response_compression() yield _RESPONSE with self._condition: self._serviced = True self._condition.notify_all() def peer(self): with self._condition: return self._peer def block_until_serviced(self): with self._condition: while not self._serviced: self._condition.wait() class _BlockingIterator(object): def __init__(self, upstream): self._condition = threading.Condition() self._upstream = upstream self._allowed = [] def __iter__(self): return self def next(self): with self._condition: while True: if self._allowed is None: raise StopIteration() elif self._allowed: return self._allowed.pop(0) else: self._condition.wait() def allow(self): with self._condition: try: self._allowed.append(next(self._upstream)) except StopIteration: self._allowed = None self._condition.notify_all() class BetaFeaturesTest(unittest.TestCase): def setUp(self): self._servicer = _Servicer() method_implementations = { (_GROUP, _UNARY_UNARY): utilities.unary_unary_inline(self._servicer.unary_unary), (_GROUP, _UNARY_STREAM): utilities.unary_stream_inline(self._servicer.unary_stream), (_GROUP, _STREAM_UNARY): utilities.stream_unary_inline(self._servicer.stream_unary), (_GROUP, _STREAM_STREAM): utilities.stream_stream_inline(self._servicer.stream_stream), } cardinalities = { _UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY, _UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM, _STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY, _STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM, } server_options = implementations.server_options( thread_pool_size=test_constants.POOL_SIZE) self._server = implementations.server( method_implementations, options=server_options) server_credentials = implementations.ssl_server_credentials( [(resources.private_key(), resources.certificate_chain(),),]) port = self._server.add_secure_port('[::]:0', server_credentials) self._server.start() self._client_credentials = implementations.ssl_client_credentials( resources.test_root_certificates(), None, None) channel = test_utilities.not_really_secure_channel( 'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE) stub_options = implementations.stub_options( thread_pool_size=test_constants.POOL_SIZE) self._dynamic_stub = implementations.dynamic_stub( channel, _GROUP, cardinalities, options=stub_options) def tearDown(self): self._dynamic_stub = None self._server.stop(test_constants.SHORT_TIMEOUT).wait() def test_unary_unary(self): call_options = interfaces.grpc_call_options( disable_compression=True, credentials=self._client_credentials) response = getattr(self._dynamic_stub, _UNARY_UNARY)( _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) self.assertEqual(_RESPONSE, response) self.assertIsNotNone(self._servicer.peer()) def test_unary_stream(self): call_options = interfaces.grpc_call_options( disable_compression=True, credentials=self._client_credentials) response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)( _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) def test_stream_unary(self): call_options = interfaces.grpc_call_options( credentials=self._client_credentials) request_iterator = _BlockingIterator(iter((_REQUEST,))) response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future( request_iterator, test_constants.LONG_TIMEOUT, protocol_options=call_options) response_future.protocol_context().disable_next_request_compression() request_iterator.allow() response_future.protocol_context().disable_next_request_compression() request_iterator.allow() self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) self.assertEqual(_RESPONSE, response_future.result()) def test_stream_stream(self): call_options = interfaces.grpc_call_options( credentials=self._client_credentials) request_iterator = _BlockingIterator(iter((_REQUEST,))) response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)( request_iterator, test_constants.SHORT_TIMEOUT, protocol_options=call_options) response_iterator.protocol_context().disable_next_request_compression() request_iterator.allow() response = next(response_iterator) response_iterator.protocol_context().disable_next_request_compression() request_iterator.allow() self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) self.assertEqual(_RESPONSE, response) if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/MANIFEST.in0000644000175000017500000000012012600663151021100 0ustar apollockapollockgraft grpc_interop graft grpc_test include commands.py include requirements.txt grpc-0.11.1/src/python/grpcio_test/commands.py0000644000175000017500000000421012600663151021521 0ustar apollockapollock# 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. """Provides distutils command classes for the GRPC Python test setup process.""" import os import os.path import sys import setuptools class RunTests(setuptools.Command): """Command to run all tests via py.test.""" description = '' user_options = [('pytest-args=', 'a', 'arguments to pass to py.test')] def initialize_options(self): self.pytest_args = [] def finalize_options(self): pass def run(self): # We import here to ensure that setup.py has had a chance to install the # relevant package eggs first. import pytest result = pytest.main(self.pytest_args) if result != 0: raise SystemExit(result) grpc-0.11.1/src/python/grpcio_test/setup.py0000644000175000017500000000555612600663151021076 0ustar apollockapollock# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """A setup module for the GRPC Python interop testing package.""" import os import os.path import setuptools # Ensure we're in the proper directory whether or not we're being used by pip. os.chdir(os.path.dirname(os.path.abspath(__file__))) # Break import-style to ensure we can actually find our commands module. import commands _PACKAGES = setuptools.find_packages('.', exclude=['*._cython', '*._cython.*']) _PACKAGE_DIRECTORIES = { '': '.', } _PACKAGE_DATA = { 'grpc_interop': [ 'credentials/ca.pem', 'credentials/server1.key', 'credentials/server1.pem', ], 'grpc_protoc_plugin': [ 'test.proto', ], 'grpc_test': [ 'credentials/ca.pem', 'credentials/server1.key', 'credentials/server1.pem', ], } _SETUP_REQUIRES = ( 'pytest>=2.6', 'pytest-cov>=2.0', 'pytest-xdist>=1.11', 'pytest-timeout>=0.5', ) _INSTALL_REQUIRES = ( 'oauth2client>=1.4.7', 'grpcio>=0.11.0b0', # TODO(issue 3321): Unpin protobuf dependency. 'protobuf==3.0.0a3', ) _COMMAND_CLASS = { 'test': commands.RunTests } setuptools.setup( name='grpcio_test', version='0.11.0b0', packages=_PACKAGES, package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA, install_requires=_INSTALL_REQUIRES + _SETUP_REQUIRES, setup_requires=_SETUP_REQUIRES, cmdclass=_COMMAND_CLASS, ) grpc-0.11.1/src/python/grpcio_test/requirements.txt0000644000175000017500000000014612600663151022636 0ustar apollockapollockgrpcio>=0.11.0b0 oauth2client>=1.4.7 protobuf>=3.0.0a3 pytest>=2.6 pytest-cov>=2.0 pytest-xdist>=1.11 grpc-0.11.1/src/python/grpcio_test/.gitignore0000644000175000017500000000013312600663151021336 0ustar apollockapollockMANIFEST *.egg-info/ build/ dist/ *.egg *.egg/ *.eggs/ .coverage .coverage.* nosetests.xml grpc-0.11.1/src/python/grpcio_test/grpc_interop/0000755000175000017500000000000012600663151022044 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py0000644000175000017500000000424712600663151027200 0ustar apollockapollock# 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. """Insecure client-server interoperability as a unit test.""" import unittest from grpc.early_adopter import implementations from grpc_interop import _interop_test_case from grpc_interop import methods class InsecureInteropTest( _interop_test_case.InteropTestCase, unittest.TestCase): def setUp(self): self.server = implementations.server( methods.SERVICE_NAME, methods.SERVER_METHODS, 0) self.server.start() port = self.server.port() self.stub = implementations.stub( methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port) def tearDown(self): self.server.stop() if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_interop/server.py0000644000175000017500000000535012600663151023727 0ustar apollockapollock# 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. """The Python implementation of the GRPC interoperability test server.""" import argparse import logging import time from grpc.early_adopter import implementations from grpc_interop import methods from grpc_interop import resources _ONE_DAY_IN_SECONDS = 60 * 60 * 24 def serve(): parser = argparse.ArgumentParser() parser.add_argument( '--port', help='the port on which to serve', type=int) parser.add_argument( '--use_tls', help='require a secure connection', dest='use_tls', action='store_true') args = parser.parse_args() if args.use_tls: private_key = resources.private_key() certificate_chain = resources.certificate_chain() server = implementations.server( methods.SERVICE_NAME, methods.SERVER_METHODS, args.port, private_key=private_key, certificate_chain=certificate_chain) else: server = implementations.server( methods.SERVICE_NAME, methods.SERVER_METHODS, args.port) server.start() logging.info('Server serving.') try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except BaseException as e: logging.info('Caught exception "%s"; stopping server...', e) server.stop() logging.info('Server stopped; exiting.') if __name__ == '__main__': serve() grpc-0.11.1/src/python/grpcio_test/grpc_interop/methods.py0000644000175000017500000003517712600663151024076 0ustar apollockapollock# 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. """Implementations of interoperability test methods.""" import enum import json import os import threading import time from oauth2client import client as oauth2client_client from grpc.framework.alpha import utilities from grpc.framework.alpha import exceptions from grpc_interop import empty_pb2 from grpc_interop import messages_pb2 _TIMEOUT = 7 def _empty_call(request, unused_context): return empty_pb2.Empty() _CLIENT_EMPTY_CALL = utilities.unary_unary_invocation_description( empty_pb2.Empty.SerializeToString, empty_pb2.Empty.FromString) _SERVER_EMPTY_CALL = utilities.unary_unary_service_description( _empty_call, empty_pb2.Empty.FromString, empty_pb2.Empty.SerializeToString) def _unary_call(request, unused_context): return messages_pb2.SimpleResponse( payload=messages_pb2.Payload( type=messages_pb2.COMPRESSABLE, body=b'\x00' * request.response_size)) _CLIENT_UNARY_CALL = utilities.unary_unary_invocation_description( messages_pb2.SimpleRequest.SerializeToString, messages_pb2.SimpleResponse.FromString) _SERVER_UNARY_CALL = utilities.unary_unary_service_description( _unary_call, messages_pb2.SimpleRequest.FromString, messages_pb2.SimpleResponse.SerializeToString) def _streaming_output_call(request, unused_context): for response_parameters in request.response_parameters: yield messages_pb2.StreamingOutputCallResponse( payload=messages_pb2.Payload( type=request.response_type, body=b'\x00' * response_parameters.size)) _CLIENT_STREAMING_OUTPUT_CALL = utilities.unary_stream_invocation_description( messages_pb2.StreamingOutputCallRequest.SerializeToString, messages_pb2.StreamingOutputCallResponse.FromString) _SERVER_STREAMING_OUTPUT_CALL = utilities.unary_stream_service_description( _streaming_output_call, messages_pb2.StreamingOutputCallRequest.FromString, messages_pb2.StreamingOutputCallResponse.SerializeToString) def _streaming_input_call(request_iterator, unused_context): aggregate_size = 0 for request in request_iterator: if request.payload and request.payload.body: aggregate_size += len(request.payload.body) return messages_pb2.StreamingInputCallResponse( aggregated_payload_size=aggregate_size) _CLIENT_STREAMING_INPUT_CALL = utilities.stream_unary_invocation_description( messages_pb2.StreamingInputCallRequest.SerializeToString, messages_pb2.StreamingInputCallResponse.FromString) _SERVER_STREAMING_INPUT_CALL = utilities.stream_unary_service_description( _streaming_input_call, messages_pb2.StreamingInputCallRequest.FromString, messages_pb2.StreamingInputCallResponse.SerializeToString) def _full_duplex_call(request_iterator, unused_context): for request in request_iterator: yield messages_pb2.StreamingOutputCallResponse( payload=messages_pb2.Payload( type=request.payload.type, body=b'\x00' * request.response_parameters[0].size)) _CLIENT_FULL_DUPLEX_CALL = utilities.stream_stream_invocation_description( messages_pb2.StreamingOutputCallRequest.SerializeToString, messages_pb2.StreamingOutputCallResponse.FromString) _SERVER_FULL_DUPLEX_CALL = utilities.stream_stream_service_description( _full_duplex_call, messages_pb2.StreamingOutputCallRequest.FromString, messages_pb2.StreamingOutputCallResponse.SerializeToString) # NOTE(nathaniel): Apparently this is the same as the full-duplex call? _CLIENT_HALF_DUPLEX_CALL = utilities.stream_stream_invocation_description( messages_pb2.StreamingOutputCallRequest.SerializeToString, messages_pb2.StreamingOutputCallResponse.FromString) _SERVER_HALF_DUPLEX_CALL = utilities.stream_stream_service_description( _full_duplex_call, messages_pb2.StreamingOutputCallRequest.FromString, messages_pb2.StreamingOutputCallResponse.SerializeToString) SERVICE_NAME = 'grpc.testing.TestService' _EMPTY_CALL_METHOD_NAME = 'EmptyCall' _UNARY_CALL_METHOD_NAME = 'UnaryCall' _STREAMING_OUTPUT_CALL_METHOD_NAME = 'StreamingOutputCall' _STREAMING_INPUT_CALL_METHOD_NAME = 'StreamingInputCall' _FULL_DUPLEX_CALL_METHOD_NAME = 'FullDuplexCall' _HALF_DUPLEX_CALL_METHOD_NAME = 'HalfDuplexCall' CLIENT_METHODS = { _EMPTY_CALL_METHOD_NAME: _CLIENT_EMPTY_CALL, _UNARY_CALL_METHOD_NAME: _CLIENT_UNARY_CALL, _STREAMING_OUTPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_OUTPUT_CALL, _STREAMING_INPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_INPUT_CALL, _FULL_DUPLEX_CALL_METHOD_NAME: _CLIENT_FULL_DUPLEX_CALL, _HALF_DUPLEX_CALL_METHOD_NAME: _CLIENT_HALF_DUPLEX_CALL, } SERVER_METHODS = { _EMPTY_CALL_METHOD_NAME: _SERVER_EMPTY_CALL, _UNARY_CALL_METHOD_NAME: _SERVER_UNARY_CALL, _STREAMING_OUTPUT_CALL_METHOD_NAME: _SERVER_STREAMING_OUTPUT_CALL, _STREAMING_INPUT_CALL_METHOD_NAME: _SERVER_STREAMING_INPUT_CALL, _FULL_DUPLEX_CALL_METHOD_NAME: _SERVER_FULL_DUPLEX_CALL, _HALF_DUPLEX_CALL_METHOD_NAME: _SERVER_HALF_DUPLEX_CALL, } def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope): with stub: request = messages_pb2.SimpleRequest( response_type=messages_pb2.COMPRESSABLE, response_size=314159, payload=messages_pb2.Payload(body=b'\x00' * 271828), fill_username=fill_username, fill_oauth_scope=fill_oauth_scope) response_future = stub.UnaryCall.async(request, _TIMEOUT) response = response_future.result() if response.payload.type is not messages_pb2.COMPRESSABLE: raise ValueError( 'response payload type is "%s"!' % type(response.payload.type)) if len(response.payload.body) != 314159: raise ValueError( 'response body of incorrect size %d!' % len(response.payload.body)) return response def _empty_unary(stub): with stub: response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT) if not isinstance(response, empty_pb2.Empty): raise TypeError( 'response is of type "%s", not empty_pb2.Empty!', type(response)) def _large_unary(stub): _large_unary_common_behavior(stub, False, False) def _client_streaming(stub): with stub: payload_body_sizes = (27182, 8, 1828, 45904) payloads = ( messages_pb2.Payload(body=b'\x00' * size) for size in payload_body_sizes) requests = ( messages_pb2.StreamingInputCallRequest(payload=payload) for payload in payloads) response = stub.StreamingInputCall(requests, _TIMEOUT) if response.aggregated_payload_size != 74922: raise ValueError( 'incorrect size %d!' % response.aggregated_payload_size) def _server_streaming(stub): sizes = (31415, 9, 2653, 58979) with stub: request = messages_pb2.StreamingOutputCallRequest( response_type=messages_pb2.COMPRESSABLE, response_parameters=( messages_pb2.ResponseParameters(size=sizes[0]), messages_pb2.ResponseParameters(size=sizes[1]), messages_pb2.ResponseParameters(size=sizes[2]), messages_pb2.ResponseParameters(size=sizes[3]), )) response_iterator = stub.StreamingOutputCall(request, _TIMEOUT) for index, response in enumerate(response_iterator): if response.payload.type != messages_pb2.COMPRESSABLE: raise ValueError( 'response body of invalid type %s!' % response.payload.type) if len(response.payload.body) != sizes[index]: raise ValueError( 'response body of invalid size %d!' % len(response.payload.body)) def _cancel_after_begin(stub): with stub: sizes = (27182, 8, 1828, 45904) payloads = [messages_pb2.Payload(body=b'\x00' * size) for size in sizes] requests = [messages_pb2.StreamingInputCallRequest(payload=payload) for payload in payloads] responses = stub.StreamingInputCall.async(requests, _TIMEOUT) responses.cancel() if not responses.cancelled(): raise ValueError('expected call to be cancelled') class _Pipe(object): def __init__(self): self._condition = threading.Condition() self._values = [] self._open = True def __iter__(self): return self def next(self): with self._condition: while not self._values and self._open: self._condition.wait() if self._values: return self._values.pop(0) else: raise StopIteration() def add(self, value): with self._condition: self._values.append(value) self._condition.notify() def close(self): with self._condition: self._open = False self._condition.notify() def __enter__(self): return self def __exit__(self, type, value, traceback): self.close() def _ping_pong(stub): request_response_sizes = (31415, 9, 2653, 58979) request_payload_sizes = (27182, 8, 1828, 45904) with stub, _Pipe() as pipe: response_iterator = stub.FullDuplexCall(pipe, _TIMEOUT) print 'Starting ping-pong with response iterator %s' % response_iterator for response_size, payload_size in zip( request_response_sizes, request_payload_sizes): request = messages_pb2.StreamingOutputCallRequest( response_type=messages_pb2.COMPRESSABLE, response_parameters=(messages_pb2.ResponseParameters( size=response_size),), payload=messages_pb2.Payload(body=b'\x00' * payload_size)) pipe.add(request) response = next(response_iterator) if response.payload.type != messages_pb2.COMPRESSABLE: raise ValueError( 'response body of invalid type %s!' % response.payload.type) if len(response.payload.body) != response_size: raise ValueError( 'response body of invalid size %d!' % len(response.payload.body)) def _cancel_after_first_response(stub): request_response_sizes = (31415, 9, 2653, 58979) request_payload_sizes = (27182, 8, 1828, 45904) with stub, _Pipe() as pipe: response_iterator = stub.FullDuplexCall(pipe, _TIMEOUT) response_size = request_response_sizes[0] payload_size = request_payload_sizes[0] request = messages_pb2.StreamingOutputCallRequest( response_type=messages_pb2.COMPRESSABLE, response_parameters=(messages_pb2.ResponseParameters( size=response_size),), payload=messages_pb2.Payload(body=b'\x00' * payload_size)) pipe.add(request) response = next(response_iterator) # We test the contents of `response` in the Ping Pong test - don't check # them here. response_iterator.cancel() try: next(response_iterator) except Exception: pass else: raise ValueError('expected call to be cancelled') def _timeout_on_sleeping_server(stub): request_payload_size = 27182 with stub, _Pipe() as pipe: response_iterator = stub.FullDuplexCall(pipe, 0.001) request = messages_pb2.StreamingOutputCallRequest( response_type=messages_pb2.COMPRESSABLE, payload=messages_pb2.Payload(body=b'\x00' * request_payload_size)) pipe.add(request) time.sleep(0.1) try: next(response_iterator) except exceptions.ExpirationError: pass else: raise ValueError('expected call to exceed deadline') def _compute_engine_creds(stub, args): response = _large_unary_common_behavior(stub, True, True) if args.default_service_account != response.username: raise ValueError( 'expected username %s, got %s' % (args.default_service_account, response.username)) def _oauth2_auth_token(stub, args): json_key_filename = os.environ[ oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS] wanted_email = json.load(open(json_key_filename, 'rb'))['client_email'] response = _large_unary_common_behavior(stub, True, True) if wanted_email != response.username: raise ValueError( 'expected username %s, got %s' % (wanted_email, response.username)) if args.oauth_scope.find(response.oauth_scope) == -1: raise ValueError( 'expected to find oauth scope "%s" in received "%s"' % (response.oauth_scope, args.oauth_scope)) @enum.unique class TestCase(enum.Enum): EMPTY_UNARY = 'empty_unary' LARGE_UNARY = 'large_unary' SERVER_STREAMING = 'server_streaming' CLIENT_STREAMING = 'client_streaming' PING_PONG = 'ping_pong' CANCEL_AFTER_BEGIN = 'cancel_after_begin' CANCEL_AFTER_FIRST_RESPONSE = 'cancel_after_first_response' COMPUTE_ENGINE_CREDS = 'compute_engine_creds' OAUTH2_AUTH_TOKEN = 'oauth2_auth_token' TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server' def test_interoperability(self, stub, args): if self is TestCase.EMPTY_UNARY: _empty_unary(stub) elif self is TestCase.LARGE_UNARY: _large_unary(stub) elif self is TestCase.SERVER_STREAMING: _server_streaming(stub) elif self is TestCase.CLIENT_STREAMING: _client_streaming(stub) elif self is TestCase.PING_PONG: _ping_pong(stub) elif self is TestCase.CANCEL_AFTER_BEGIN: _cancel_after_begin(stub) elif self is TestCase.CANCEL_AFTER_FIRST_RESPONSE: _cancel_after_first_response(stub) elif self is TestCase.TIMEOUT_ON_SLEEPING_SERVER: _timeout_on_sleeping_server(stub) elif self is TestCase.COMPUTE_ENGINE_CREDS: _compute_engine_creds(stub, args) elif self is TestCase.OAUTH2_AUTH_TOKEN: _oauth2_auth_token(stub, args) else: raise NotImplementedError('Test case "%s" not implemented!' % self.name) grpc-0.11.1/src/python/grpcio_test/grpc_interop/test_pb2.py0000644000175000017500000002027112600663151024142 0ustar apollockapollock# Generated by the protocol buffer compiler. DO NOT EDIT! # source: test/cpp/interop/test.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() from test.cpp.interop import empty_pb2 as test_dot_cpp_dot_interop_dot_empty__pb2 from test.cpp.interop import messages_pb2 as test_dot_cpp_dot_interop_dot_messages__pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='test/cpp/interop/test.proto', package='grpc.testing', serialized_pb=_b('\n\x1btest/cpp/interop/test.proto\x12\x0cgrpc.testing\x1a\x1ctest/cpp/interop/empty.proto\x1a\x1ftest/cpp/interop/messages.proto2\xbb\x04\n\x0bTestService\x12\x35\n\tEmptyCall\x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty\x12\x46\n\tUnaryCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleResponse\x12l\n\x13StreamingOutputCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse0\x01\x12i\n\x12StreamingInputCall\x12\'.grpc.testing.StreamingInputCallRequest\x1a(.grpc.testing.StreamingInputCallResponse(\x01\x12i\n\x0e\x46ullDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01\x12i\n\x0eHalfDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01') , dependencies=[test_dot_cpp_dot_interop_dot_empty__pb2.DESCRIPTOR,test_dot_cpp_dot_interop_dot_messages__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) import abc from grpc.early_adopter import implementations from grpc.framework.alpha import utilities class EarlyAdopterTestServiceServicer(object): """""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def EmptyCall(self, request, context): raise NotImplementedError() @abc.abstractmethod def UnaryCall(self, request, context): raise NotImplementedError() @abc.abstractmethod def StreamingOutputCall(self, request, context): raise NotImplementedError() @abc.abstractmethod def StreamingInputCall(self, request_iterator, context): raise NotImplementedError() @abc.abstractmethod def FullDuplexCall(self, request_iterator, context): raise NotImplementedError() @abc.abstractmethod def HalfDuplexCall(self, request_iterator, context): raise NotImplementedError() class EarlyAdopterTestServiceServer(object): """""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def start(self): raise NotImplementedError() @abc.abstractmethod def stop(self): raise NotImplementedError() class EarlyAdopterTestServiceStub(object): """""" __metaclass__ = abc.ABCMeta @abc.abstractmethod def EmptyCall(self, request): raise NotImplementedError() EmptyCall.async = None @abc.abstractmethod def UnaryCall(self, request): raise NotImplementedError() UnaryCall.async = None @abc.abstractmethod def StreamingOutputCall(self, request): raise NotImplementedError() StreamingOutputCall.async = None @abc.abstractmethod def StreamingInputCall(self, request_iterator): raise NotImplementedError() StreamingInputCall.async = None @abc.abstractmethod def FullDuplexCall(self, request_iterator): raise NotImplementedError() FullDuplexCall.async = None @abc.abstractmethod def HalfDuplexCall(self, request_iterator): raise NotImplementedError() HalfDuplexCall.async = None def early_adopter_create_TestService_server(servicer, port, private_key=None, certificate_chain=None): import test.cpp.interop.empty_pb2 import test.cpp.interop.empty_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 method_service_descriptions = { "EmptyCall": utilities.unary_unary_service_description( servicer.EmptyCall, test.cpp.interop.empty_pb2.Empty.FromString, test.cpp.interop.empty_pb2.Empty.SerializeToString, ), "FullDuplexCall": utilities.stream_stream_service_description( servicer.FullDuplexCall, test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString, test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString, ), "HalfDuplexCall": utilities.stream_stream_service_description( servicer.HalfDuplexCall, test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString, test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString, ), "StreamingInputCall": utilities.stream_unary_service_description( servicer.StreamingInputCall, test.cpp.interop.messages_pb2.StreamingInputCallRequest.FromString, test.cpp.interop.messages_pb2.StreamingInputCallResponse.SerializeToString, ), "StreamingOutputCall": utilities.unary_stream_service_description( servicer.StreamingOutputCall, test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString, test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString, ), "UnaryCall": utilities.unary_unary_service_description( servicer.UnaryCall, test.cpp.interop.messages_pb2.SimpleRequest.FromString, test.cpp.interop.messages_pb2.SimpleResponse.SerializeToString, ), } return implementations.server("grpc.testing.TestService", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain) def early_adopter_create_TestService_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None): import test.cpp.interop.empty_pb2 import test.cpp.interop.empty_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 import test.cpp.interop.messages_pb2 method_invocation_descriptions = { "EmptyCall": utilities.unary_unary_invocation_description( test.cpp.interop.empty_pb2.Empty.SerializeToString, test.cpp.interop.empty_pb2.Empty.FromString, ), "FullDuplexCall": utilities.stream_stream_invocation_description( test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString, test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString, ), "HalfDuplexCall": utilities.stream_stream_invocation_description( test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString, test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString, ), "StreamingInputCall": utilities.stream_unary_invocation_description( test.cpp.interop.messages_pb2.StreamingInputCallRequest.SerializeToString, test.cpp.interop.messages_pb2.StreamingInputCallResponse.FromString, ), "StreamingOutputCall": utilities.unary_stream_invocation_description( test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString, test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString, ), "UnaryCall": utilities.unary_unary_invocation_description( test.cpp.interop.messages_pb2.SimpleRequest.SerializeToString, test.cpp.interop.messages_pb2.SimpleResponse.FromString, ), } return implementations.stub("grpc.testing.TestService", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override) # @@protoc_insertion_point(module_scope) grpc-0.11.1/src/python/grpcio_test/grpc_interop/credentials/0000755000175000017500000000000012600663151024341 5ustar apollockapollockgrpc-0.11.1/src/python/grpcio_test/grpc_interop/credentials/server1.pem0000755000175000017500000000170412600663151026440 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= -----END CERTIFICATE----- grpc-0.11.1/src/python/grpcio_test/grpc_interop/credentials/ca.pem0000755000175000017500000000152712600663151025437 0ustar apollockapollock-----BEGIN CERTIFICATE----- MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 +L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG Dfcog5wrJytaQ6UA0wE= -----END CERTIFICATE----- grpc-0.11.1/src/python/grpcio_test/grpc_interop/credentials/README0000644000175000017500000000006412600663151025221 0ustar apollockapollockThese are test keys *NOT* to be used in production. grpc-0.11.1/src/python/grpcio_test/grpc_interop/credentials/server1.key0000755000175000017500000000162012600663151026444 0ustar apollockapollock-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf 3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR 81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe F98XJ7tIFfJq -----END PRIVATE KEY----- grpc-0.11.1/src/python/grpcio_test/grpc_interop/resources.py0000644000175000017500000000427612600663151024441 0ustar apollockapollock# 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. """Constants and functions for data used in interoperability testing.""" import os import pkg_resources _ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem' _PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key' _CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem' def test_root_certificates(): return pkg_resources.resource_string( __name__, _ROOT_CERTIFICATES_RESOURCE_PATH) def prod_root_certificates(): return open(os.environ['SSL_CERT_FILE'], mode='rb').read() def private_key(): return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH) def certificate_chain(): return pkg_resources.resource_string( __name__, _CERTIFICATE_CHAIN_RESOURCE_PATH) grpc-0.11.1/src/python/grpcio_test/grpc_interop/_interop_test_case.py0000644000175000017500000000524712600663151026277 0ustar apollockapollock# 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. """Common code for unit tests of the interoperability test code.""" from grpc_interop import methods class InteropTestCase(object): """Unit test methods. This class must be mixed in with unittest.TestCase and a class that defines setUp and tearDown methods that manage a stub attribute. """ def testEmptyUnary(self): methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub, None) def testLargeUnary(self): methods.TestCase.LARGE_UNARY.test_interoperability(self.stub, None) def testServerStreaming(self): methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub, None) def testClientStreaming(self): methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub, None) def testPingPong(self): methods.TestCase.PING_PONG.test_interoperability(self.stub, None) def testCancelAfterBegin(self): methods.TestCase.CANCEL_AFTER_BEGIN.test_interoperability(self.stub, None) def testCancelAfterFirstResponse(self): methods.TestCase.CANCEL_AFTER_FIRST_RESPONSE.test_interoperability(self.stub, None) def testTimeoutOnSleepingServer(self): methods.TestCase.TIMEOUT_ON_SLEEPING_SERVER.test_interoperability(self.stub, None) grpc-0.11.1/src/python/grpcio_test/grpc_interop/client.py0000644000175000017500000001055312600663151023700 0ustar apollockapollock# 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. """The Python implementation of the GRPC interoperability test client.""" import argparse from oauth2client import client as oauth2client_client from grpc.early_adopter import implementations from grpc_interop import methods from grpc_interop import resources _ONE_DAY_IN_SECONDS = 60 * 60 * 24 def _args(): parser = argparse.ArgumentParser() parser.add_argument( '--server_host', help='the host to which to connect', type=str) parser.add_argument( '--server_port', help='the port to which to connect', type=int) parser.add_argument( '--test_case', help='the test case to execute', type=str) parser.add_argument( '--use_tls', help='require a secure connection', dest='use_tls', action='store_true') parser.add_argument( '--use_test_ca', help='replace platform root CAs with ca.pem', action='store_true') parser.add_argument( '--server_host_override', help='the server host to which to claim to connect', type=str) parser.add_argument('--oauth_scope', help='scope for OAuth tokens', type=str) parser.add_argument( '--default_service_account', help='email address of the default service account', type=str) return parser.parse_args() def _oauth_access_token(args): credentials = oauth2client_client.GoogleCredentials.get_application_default() scoped_credentials = credentials.create_scoped([args.oauth_scope]) return scoped_credentials.get_access_token().access_token def _stub(args): if args.oauth_scope: if args.test_case == 'oauth2_auth_token': access_token = _oauth_access_token(args) metadata_transformer = lambda x: [ ('Authorization', 'Bearer %s' % access_token)] else: metadata_transformer = lambda x: [ ('Authorization', 'Bearer %s' % _oauth_access_token(args))] else: metadata_transformer = lambda x: [] if args.use_tls: if args.use_test_ca: root_certificates = resources.test_root_certificates() else: root_certificates = resources.prod_root_certificates() stub = implementations.stub( methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host, args.server_port, metadata_transformer=metadata_transformer, secure=True, root_certificates=root_certificates, server_host_override=args.server_host_override) else: stub = implementations.stub( methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host, args.server_port, secure=False) return stub def _test_case_from_arg(test_case_arg): for test_case in methods.TestCase: if test_case_arg == test_case.value: return test_case else: raise ValueError('No test case "%s"!' % test_case_arg) def _test_interoperability(): args = _args() stub = _stub(args) test_case = _test_case_from_arg(args.test_case) test_case.test_interoperability(stub, args) if __name__ == '__main__': _test_interoperability() grpc-0.11.1/src/python/grpcio_test/grpc_interop/__init__.py0000644000175000017500000000277212600663151024165 0ustar apollockapollock# 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. grpc-0.11.1/src/python/grpcio_test/grpc_interop/_secure_interop_test.py0000644000175000017500000000473112600663151026647 0ustar apollockapollock# 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. """Secure client-server interoperability as a unit test.""" import unittest from grpc.early_adopter import implementations from grpc_interop import _interop_test_case from grpc_interop import methods from grpc_interop import resources _SERVER_HOST_OVERRIDE = 'foo.test.google.fr' class SecureInteropTest( _interop_test_case.InteropTestCase, unittest.TestCase): def setUp(self): self.server = implementations.server( methods.SERVICE_NAME, methods.SERVER_METHODS, 0, private_key=resources.private_key(), certificate_chain=resources.certificate_chain()) self.server.start() port = self.server.port() self.stub = implementations.stub( methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port, secure=True, root_certificates=resources.test_root_certificates(), server_host_override=_SERVER_HOST_OVERRIDE) def tearDown(self): self.server.stop() if __name__ == '__main__': unittest.main(verbosity=2) grpc-0.11.1/src/python/grpcio_test/grpc_interop/messages_pb2.py0000644000175000017500000004025412600663151024775 0ustar apollockapollock# Generated by the protocol buffer compiler. DO NOT EDIT! # source: test/cpp/interop/messages.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='test/cpp/interop/messages.proto', package='grpc.testing', serialized_pb=_b('\n\x1ftest/cpp/interop/messages.proto\x12\x0cgrpc.testing\"@\n\x07Payload\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x0c\n\x04\x62ody\x18\x02 \x01(\x0c\"\xb1\x01\n\rSimpleRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x15\n\rresponse_size\x18\x02 \x01(\x05\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x15\n\rfill_username\x18\x04 \x01(\x08\x12\x18\n\x10\x66ill_oauth_scope\x18\x05 \x01(\x08\"_\n\x0eSimpleResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x13\n\x0boauth_scope\x18\x03 \x01(\t\"C\n\x19StreamingInputCallRequest\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\"=\n\x1aStreamingInputCallResponse\x12\x1f\n\x17\x61ggregated_payload_size\x18\x01 \x01(\x05\"7\n\x12ResponseParameters\x12\x0c\n\x04size\x18\x01 \x01(\x05\x12\x13\n\x0binterval_us\x18\x02 \x01(\x05\"\xb5\x01\n\x1aStreamingOutputCallRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12=\n\x13response_parameters\x18\x02 \x03(\x0b\x32 .grpc.testing.ResponseParameters\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\"E\n\x1bStreamingOutputCallResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload*?\n\x0bPayloadType\x12\x10\n\x0c\x43OMPRESSABLE\x10\x00\x12\x12\n\x0eUNCOMPRESSABLE\x10\x01\x12\n\n\x06RANDOM\x10\x02') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) _PAYLOADTYPE = _descriptor.EnumDescriptor( name='PayloadType', full_name='grpc.testing.PayloadType', filename=None, file=DESCRIPTOR, values=[ _descriptor.EnumValueDescriptor( name='COMPRESSABLE', index=0, number=0, options=None, type=None), _descriptor.EnumValueDescriptor( name='UNCOMPRESSABLE', index=1, number=1, options=None, type=None), _descriptor.EnumValueDescriptor( name='RANDOM', index=2, number=2, options=None, type=None), ], containing_type=None, options=None, serialized_start=836, serialized_end=899, ) _sym_db.RegisterEnumDescriptor(_PAYLOADTYPE) PayloadType = enum_type_wrapper.EnumTypeWrapper(_PAYLOADTYPE) COMPRESSABLE = 0 UNCOMPRESSABLE = 1 RANDOM = 2 _PAYLOAD = _descriptor.Descriptor( name='Payload', full_name='grpc.testing.Payload', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='type', full_name='grpc.testing.Payload.type', index=0, number=1, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='body', full_name='grpc.testing.Payload.body', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=49, serialized_end=113, ) _SIMPLEREQUEST = _descriptor.Descriptor( name='SimpleRequest', full_name='grpc.testing.SimpleRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='response_type', full_name='grpc.testing.SimpleRequest.response_type', index=0, number=1, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='response_size', full_name='grpc.testing.SimpleRequest.response_size', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='payload', full_name='grpc.testing.SimpleRequest.payload', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='fill_username', full_name='grpc.testing.SimpleRequest.fill_username', index=3, number=4, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='fill_oauth_scope', full_name='grpc.testing.SimpleRequest.fill_oauth_scope', index=4, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=116, serialized_end=293, ) _SIMPLERESPONSE = _descriptor.Descriptor( name='SimpleResponse', full_name='grpc.testing.SimpleResponse', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='payload', full_name='grpc.testing.SimpleResponse.payload', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='username', full_name='grpc.testing.SimpleResponse.username', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='oauth_scope', full_name='grpc.testing.SimpleResponse.oauth_scope', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=295, serialized_end=390, ) _STREAMINGINPUTCALLREQUEST = _descriptor.Descriptor( name='StreamingInputCallRequest', full_name='grpc.testing.StreamingInputCallRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='payload', full_name='grpc.testing.StreamingInputCallRequest.payload', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=392, serialized_end=459, ) _STREAMINGINPUTCALLRESPONSE = _descriptor.Descriptor( name='StreamingInputCallResponse', full_name='grpc.testing.StreamingInputCallResponse', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='aggregated_payload_size', full_name='grpc.testing.StreamingInputCallResponse.aggregated_payload_size', index=0, number=1, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=461, serialized_end=522, ) _RESPONSEPARAMETERS = _descriptor.Descriptor( name='ResponseParameters', full_name='grpc.testing.ResponseParameters', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='size', full_name='grpc.testing.ResponseParameters.size', index=0, number=1, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='interval_us', full_name='grpc.testing.ResponseParameters.interval_us', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=524, serialized_end=579, ) _STREAMINGOUTPUTCALLREQUEST = _descriptor.Descriptor( name='StreamingOutputCallRequest', full_name='grpc.testing.StreamingOutputCallRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='response_type', full_name='grpc.testing.StreamingOutputCallRequest.response_type', index=0, number=1, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='response_parameters', full_name='grpc.testing.StreamingOutputCallRequest.response_parameters', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='payload', full_name='grpc.testing.StreamingOutputCallRequest.payload', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=582, serialized_end=763, ) _STREAMINGOUTPUTCALLRESPONSE = _descriptor.Descriptor( name='StreamingOutputCallResponse', full_name='grpc.testing.StreamingOutputCallResponse', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='payload', full_name='grpc.testing.StreamingOutputCallResponse.payload', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=765, serialized_end=834, ) _PAYLOAD.fields_by_name['type'].enum_type = _PAYLOADTYPE _SIMPLEREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE _SIMPLEREQUEST.fields_by_name['payload'].message_type = _PAYLOAD _SIMPLERESPONSE.fields_by_name['payload'].message_type = _PAYLOAD _STREAMINGINPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD _STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE _STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_parameters'].message_type = _RESPONSEPARAMETERS _STREAMINGOUTPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD _STREAMINGOUTPUTCALLRESPONSE.fields_by_name['payload'].message_type = _PAYLOAD DESCRIPTOR.message_types_by_name['Payload'] = _PAYLOAD DESCRIPTOR.message_types_by_name['SimpleRequest'] = _SIMPLEREQUEST DESCRIPTOR.message_types_by_name['SimpleResponse'] = _SIMPLERESPONSE DESCRIPTOR.message_types_by_name['StreamingInputCallRequest'] = _STREAMINGINPUTCALLREQUEST DESCRIPTOR.message_types_by_name['StreamingInputCallResponse'] = _STREAMINGINPUTCALLRESPONSE DESCRIPTOR.message_types_by_name['ResponseParameters'] = _RESPONSEPARAMETERS DESCRIPTOR.message_types_by_name['StreamingOutputCallRequest'] = _STREAMINGOUTPUTCALLREQUEST DESCRIPTOR.message_types_by_name['StreamingOutputCallResponse'] = _STREAMINGOUTPUTCALLRESPONSE DESCRIPTOR.enum_types_by_name['PayloadType'] = _PAYLOADTYPE Payload = _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), dict( DESCRIPTOR = _PAYLOAD, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.Payload) )) _sym_db.RegisterMessage(Payload) SimpleRequest = _reflection.GeneratedProtocolMessageType('SimpleRequest', (_message.Message,), dict( DESCRIPTOR = _SIMPLEREQUEST, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.SimpleRequest) )) _sym_db.RegisterMessage(SimpleRequest) SimpleResponse = _reflection.GeneratedProtocolMessageType('SimpleResponse', (_message.Message,), dict( DESCRIPTOR = _SIMPLERESPONSE, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.SimpleResponse) )) _sym_db.RegisterMessage(SimpleResponse) StreamingInputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingInputCallRequest', (_message.Message,), dict( DESCRIPTOR = _STREAMINGINPUTCALLREQUEST, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallRequest) )) _sym_db.RegisterMessage(StreamingInputCallRequest) StreamingInputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingInputCallResponse', (_message.Message,), dict( DESCRIPTOR = _STREAMINGINPUTCALLRESPONSE, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallResponse) )) _sym_db.RegisterMessage(StreamingInputCallResponse) ResponseParameters = _reflection.GeneratedProtocolMessageType('ResponseParameters', (_message.Message,), dict( DESCRIPTOR = _RESPONSEPARAMETERS, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.ResponseParameters) )) _sym_db.RegisterMessage(ResponseParameters) StreamingOutputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingOutputCallRequest', (_message.Message,), dict( DESCRIPTOR = _STREAMINGOUTPUTCALLREQUEST, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallRequest) )) _sym_db.RegisterMessage(StreamingOutputCallRequest) StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingOutputCallResponse', (_message.Message,), dict( DESCRIPTOR = _STREAMINGOUTPUTCALLRESPONSE, __module__ = 'test.cpp.interop.messages_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallResponse) )) _sym_db.RegisterMessage(StreamingOutputCallResponse) import abc from grpc.early_adopter import implementations from grpc.framework.alpha import utilities # @@protoc_insertion_point(module_scope) grpc-0.11.1/src/python/grpcio_test/grpc_interop/empty_pb2.py0000644000175000017500000000303612600663151024321 0ustar apollockapollock# Generated by the protocol buffer compiler. DO NOT EDIT! # source: test/cpp/interop/empty.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='test/cpp/interop/empty.proto', package='grpc.testing', serialized_pb=_b('\n\x1ctest/cpp/interop/empty.proto\x12\x0cgrpc.testing\"\x07\n\x05\x45mpty') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) _EMPTY = _descriptor.Descriptor( name='Empty', full_name='grpc.testing.Empty', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=46, serialized_end=53, ) DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), dict( DESCRIPTOR = _EMPTY, __module__ = 'test.cpp.interop.empty_pb2' # @@protoc_insertion_point(class_scope:grpc.testing.Empty) )) _sym_db.RegisterMessage(Empty) import abc from grpc.early_adopter import implementations from grpc.framework.alpha import utilities # @@protoc_insertion_point(module_scope) grpc-0.11.1/src/ruby/0000755000175000017500000000000012600663151014467 5ustar apollockapollockgrpc-0.11.1/src/ruby/README.md0000644000175000017500000000552112600663151015751 0ustar apollockapollockgRPC Ruby ========= A Ruby implementation of gRPC. Status ------ Alpha : Ready for early adopters PREREQUISITES ------------- - Ruby 2.x. The gRPC API uses keyword args. - [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core. INSTALLATION --------------- **Linux (Debian):** Add [Debian jessie-backports][] to your `sources.list` file. Example: ```sh echo "deb http://http.debian.net/debian jessie-backports main" | \ sudo tee -a /etc/apt/sources.list ``` Install the gRPC Debian package ```sh sudo apt-get update sudo apt-get install libgrpc-dev ``` Install the gRPC Ruby package ```sh gem install grpc ``` **Mac OS X** Install [homebrew][]. Run the following command to install gRPC Ruby. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s ruby ``` This will download and run the [gRPC install script][], then install the latest version of gRPC Ruby gem. It also installs Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin for ruby. BUILD FROM SOURCE --------------------- - Clone this repository - Install Ruby 2.x. Consider doing this with [RVM](http://rvm.io), it's a nice way of controlling the exact ruby version that's used. ```sh $ command curl -sSL https://rvm.io/mpapis.asc | gpg --import - $ \curl -sSL https://get.rvm.io | bash -s stable --ruby=ruby-2 $ $ # follow the instructions to ensure that your're using the latest stable version of Ruby $ # and that the rvm command is installed ``` - Make sure your run `source $HOME/.rvm/scripts/rvm` as instructed to complete the set up of RVM - Install [bundler](http://bundler.io/) ``` $ gem install bundler ``` - Finally, build and install the gRPC gem locally. ```sh $ # from this directory $ bundle install # creates the ruby bundle, including building the grpc extension $ rake # runs the unit tests, see rake -T for other options ``` DOCUMENTATION ------------- - rubydoc for the gRPC gem is available online at [rubydoc][]. - the gRPC Ruby reference documentation is available online at [grpc.io][] CONTENTS -------- Directory structure is the layout for [ruby extensions][] - ext: the gRPC ruby extension - lib: the entrypoint gRPC ruby library to be used in a 'require' statement - spec: Rspec unittests - bin: example gRPC clients and servers, e.g, ```ruby stub = Math::Math::Stub.new('my.test.math.server.com:8080') req = Math::DivArgs.new(dividend: 7, divisor: 3) GRPC.logger.info("div(7/3): req=#{req.inspect}") resp = stub.div(req) GRPC.logger.info("Answer: #{resp.inspect}") ``` [homebrew]:http://brew.sh [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [ruby extensions]:http://guides.rubygems.org/gems-with-extensions/ [rubydoc]: http://www.rubydoc.info/gems/grpc [grpc.io]: http://www.grpc.io/docs/installation/ruby.html [Debian jessie-backports]:http://backports.debian.org/Instructions/ grpc-0.11.1/src/ruby/Rakefile0000755000175000017500000000350512600663151016142 0ustar apollockapollock# -*- ruby -*- require 'rake/extensiontask' require 'rspec/core/rake_task' require 'rubocop/rake_task' require 'bundler/gem_tasks' # Add rubocop style checking tasks RuboCop::RakeTask.new # Add the extension compiler task Rake::ExtensionTask.new 'grpc' do |ext| ext.lib_dir = File.join('lib', 'grpc') end # Define the test suites SPEC_SUITES = [ { id: :wrapper, title: 'wrapper layer', files: %w(spec/*.rb) }, { id: :idiomatic, title: 'idiomatic layer', dir: %w(spec/generic), tags: ['~bidi', '~server'] }, { id: :bidi, title: 'bidi tests', dir: %w(spec/generic), tag: 'bidi' }, { id: :server, title: 'rpc server thread tests', dir: %w(spec/generic), tag: 'server' }, { id: :pb, title: 'protobuf service tests', dir: %w(spec/pb) } ] namespace :suite do SPEC_SUITES.each do |suite| desc "Run all specs in the #{suite[:title]} spec suite" RSpec::Core::RakeTask.new(suite[:id]) do |t| ENV['COVERAGE_NAME'] = suite[:id].to_s spec_files = [] suite[:files].each { |f| spec_files += Dir[f] } if suite[:files] if suite[:dir] suite[:dir].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] } end helper = 'spec/spec_helper.rb' spec_files << helper unless spec_files.include?(helper) t.pattern = spec_files t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag] if suite[:tags] t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ') end end end end # Define dependencies between the suites. task 'suite:wrapper' => [:compile, :rubocop] task 'suite:idiomatic' => 'suite:wrapper' task 'suite:bidi' => 'suite:wrapper' task 'suite:server' => 'suite:wrapper' task 'suite:pb' => 'suite:server' desc 'Compiles the gRPC extension then runs all the tests' task all: ['suite:idiomatic', 'suite:bidi', 'suite:pb', 'suite:server'] task default: :all grpc-0.11.1/src/ruby/Gemfile0000755000175000017500000000013112600663151015760 0ustar apollockapollocksource 'https://rubygems.org' # Specify your gem's dependencies in grpc.gemspec gemspec grpc-0.11.1/src/ruby/ext/0000755000175000017500000000000012600663151015267 5ustar apollockapollockgrpc-0.11.1/src/ruby/ext/grpc/0000755000175000017500000000000012600663151016222 5ustar apollockapollockgrpc-0.11.1/src/ruby/ext/grpc/rb_channel.h0000644000175000017500000000352312600663151020471 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_RB_CHANNEL_H_ #define GRPC_RB_CHANNEL_H_ #include #include /* Initializes the Channel class. */ void Init_grpc_channel(); /* Gets the wrapped channel from the ruby wrapper */ grpc_channel* grpc_rb_get_wrapped_channel(VALUE v); #endif /* GRPC_RB_CHANNEL_H_ */ grpc-0.11.1/src/ruby/ext/grpc/rb_byte_buffer.h0000644000175000017500000000365012600663151021356 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_RB_BYTE_BUFFER_H_ #define GRPC_RB_BYTE_BUFFER_H_ #include #include /* Converts a char* with a length to a grpc_byte_buffer */ grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length); /* Converts a grpc_byte_buffer to a ruby string */ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer); #endif /* GRPC_RB_BYTE_BUFFER_H_ */ grpc-0.11.1/src/ruby/ext/grpc/rb_credentials.h0000644000175000017500000000360112600663151021353 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_RB_CREDENTIALS_H_ #define GRPC_RB_CREDENTIALS_H_ #include #include /* Initializes the ruby Credentials class. */ void Init_grpc_credentials(); /* Gets the wrapped credentials from the ruby wrapper */ grpc_credentials* grpc_rb_get_wrapped_credentials(VALUE v); #endif /* GRPC_RB_CREDENTIALS_H_ */ grpc-0.11.1/src/ruby/ext/grpc/rb_server.c0000644000175000017500000003172012600663151020362 0ustar apollockapollock/* * * 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 "rb_server.h" #include #include #include #include "rb_call.h" #include "rb_channel_args.h" #include "rb_completion_queue.h" #include "rb_server_credentials.h" #include "rb_grpc.h" /* grpc_rb_cServer is the ruby class that proxies grpc_server. */ static VALUE grpc_rb_cServer = Qnil; /* id_at is the constructor method of the ruby standard Time class. */ static ID id_at; /* id_insecure_server is used to indicate that a server is insecure */ static VALUE id_insecure_server; /* grpc_rb_server wraps a grpc_server. It provides a peer ruby object, 'mark' to minimize copying when a server is created from ruby. */ typedef struct grpc_rb_server { /* Holder of ruby objects involved in constructing the server */ VALUE mark; /* The actual server */ grpc_server *wrapped; } grpc_rb_server; /* Destroys server instances. */ static void grpc_rb_server_free(void *p) { grpc_rb_server *svr = NULL; if (p == NULL) { return; }; svr = (grpc_rb_server *)p; /* Deletes the wrapped object if the mark object is Qnil, which indicates that no other object is the actual owner. */ /* grpc_server_shutdown does not exist. Change this to something that does or delete it */ if (svr->wrapped != NULL && svr->mark == Qnil) { // grpc_server_shutdown(svr->wrapped); // Aborting to indicate a bug abort(); grpc_server_destroy(svr->wrapped); } xfree(p); } /* Protects the mark object from GC */ static void grpc_rb_server_mark(void *p) { grpc_rb_server *server = NULL; if (p == NULL) { return; } server = (grpc_rb_server *)p; if (server->mark != Qnil) { rb_gc_mark(server->mark); } } static const rb_data_type_t grpc_rb_server_data_type = { "grpc_server", {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block * and we might want to unlock GVL * TODO(yugui) Unlock GVL? */ 0}; /* Allocates grpc_rb_server instances. */ static VALUE grpc_rb_server_alloc(VALUE cls) { grpc_rb_server *wrapper = ALLOC(grpc_rb_server); wrapper->wrapped = NULL; wrapper->mark = Qnil; return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper); } /* call-seq: cq = CompletionQueue.new server = Server.new(cq, {'arg1': 'value1'}) Initializes server instances. */ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) { grpc_completion_queue *cq = NULL; grpc_rb_server *wrapper = NULL; grpc_server *srv = NULL; grpc_channel_args args; MEMZERO(&args, grpc_channel_args, 1); cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, wrapper); grpc_rb_hash_convert_to_channel_args(channel_args, &args); srv = grpc_server_create(&args, NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ } if (srv == NULL) { rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why"); } grpc_server_register_completion_queue(srv, cq, NULL); wrapper->wrapped = srv; /* Add the cq as the server's mark object. This ensures the ruby cq can't be GCed before the server */ wrapper->mark = cqueue; return self; } /* Clones Server instances. Gives Server a consistent implementation of Ruby's object copy/dup protocol. */ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) { grpc_rb_server *orig_srv = NULL; grpc_rb_server *copy_srv = NULL; if (copy == orig) { return copy; } /* Raise an error if orig is not a server object or a subclass. */ if (TYPE(orig) != T_DATA || RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_free) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer)); } TypedData_Get_Struct(orig, grpc_rb_server, &grpc_rb_server_data_type, orig_srv); TypedData_Get_Struct(copy, grpc_rb_server, &grpc_rb_server_data_type, copy_srv); /* use ruby's MEMCPY to make a byte-for-byte copy of the server wrapper object. */ MEMCPY(copy_srv, orig_srv, grpc_rb_server, 1); return copy; } /* request_call_stack holds various values used by the * grpc_rb_server_request_call function */ typedef struct request_call_stack { grpc_call_details details; grpc_metadata_array md_ary; } request_call_stack; /* grpc_request_call_stack_init ensures the request_call_stack is properly * initialized */ static void grpc_request_call_stack_init(request_call_stack* st) { MEMZERO(st, request_call_stack, 1); grpc_metadata_array_init(&st->md_ary); grpc_call_details_init(&st->details); st->details.method = NULL; st->details.host = NULL; } /* grpc_request_call_stack_cleanup ensures the request_call_stack is properly * cleaned up */ static void grpc_request_call_stack_cleanup(request_call_stack* st) { grpc_metadata_array_destroy(&st->md_ary); grpc_call_details_destroy(&st->details); } /* call-seq: cq = CompletionQueue.new tag = Object.new timeout = 10 server.request_call(cqueue, tag, timeout) Requests notification of a new call on a server. */ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, VALUE tag_new, VALUE timeout) { grpc_rb_server *s = NULL; grpc_call *call = NULL; grpc_event ev; grpc_call_error err; request_call_stack st; VALUE result; gpr_timespec deadline; TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); return Qnil; } else { grpc_request_call_stack_init(&st); /* call grpc_server_request_call, then wait for it to complete using * pluck_event */ err = grpc_server_request_call( s->wrapped, &call, &st.details, &st.md_ary, grpc_rb_get_wrapped_completion_queue(cqueue), grpc_rb_get_wrapped_completion_queue(cqueue), ROBJECT(tag_new)); if (err != GRPC_CALL_OK) { grpc_request_call_stack_cleanup(&st); rb_raise(grpc_rb_eCallError, "grpc_server_request_call failed: %s (code=%d)", grpc_call_error_detail_of(err), err); return Qnil; } ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout); if (ev.type == GRPC_QUEUE_TIMEOUT) { grpc_request_call_stack_cleanup(&st); return Qnil; } if (!ev.success) { grpc_request_call_stack_cleanup(&st); rb_raise(grpc_rb_eCallError, "request_call completion failed"); return Qnil; } /* build the NewServerRpc struct result */ deadline = gpr_convert_clock_type(st.details.deadline, GPR_CLOCK_REALTIME); result = rb_struct_new( grpc_rb_sNewServerRpc, rb_str_new2(st.details.method), rb_str_new2(st.details.host), rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec), INT2NUM(deadline.tv_nsec)), grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call), NULL); grpc_request_call_stack_cleanup(&st); return result; } return Qnil; } static VALUE grpc_rb_server_start(VALUE self) { grpc_rb_server *s = NULL; TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); } else { grpc_server_start(s->wrapped); } return Qnil; } /* call-seq: cq = CompletionQueue.new server = Server.new(cq, {'arg1': 'value1'}) ... // do stuff with server ... ... // to shutdown the server server.destroy(cq) ... // to shutdown the server with a timeout server.destroy(cq, timeout) Destroys server instances. */ static VALUE grpc_rb_server_destroy(int argc, VALUE *argv, VALUE self) { VALUE cqueue = Qnil; VALUE timeout = Qnil; grpc_completion_queue *cq = NULL; grpc_event ev; grpc_rb_server *s = NULL; /* "11" == 1 mandatory args, 1 (timeout) is optional */ rb_scan_args(argc, argv, "11", &cqueue, &timeout); cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped != NULL) { grpc_server_shutdown_and_notify(s->wrapped, cq, NULL); ev = grpc_rb_completion_queue_pluck_event(cqueue, Qnil, timeout); if (!ev.success) { rb_warn("server shutdown failed, cancelling the calls, objects may leak"); grpc_server_cancel_all_calls(s->wrapped); return Qfalse; } grpc_server_destroy(s->wrapped); s->wrapped = NULL; } return Qtrue; } /* call-seq: // insecure port insecure_server = Server.new(cq, {'arg1': 'value1'}) insecure_server.add_http2_port('mydomain:50051', :this_port_is_insecure) // secure port server_creds = ... secure_server = Server.new(cq, {'arg1': 'value1'}) secure_server.add_http_port('mydomain:50051', server_creds) Adds a http2 port to server */ static VALUE grpc_rb_server_add_http2_port(VALUE self, VALUE port, VALUE rb_creds) { grpc_rb_server *s = NULL; grpc_server_credentials *creds = NULL; int recvd_port = 0; TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); return Qnil; } else if (TYPE(rb_creds) == T_SYMBOL) { if (id_insecure_server != SYM2ID(rb_creds)) { rb_raise(rb_eTypeError, "bad creds symbol, want :this_port_is_insecure"); return Qnil; } recvd_port = grpc_server_add_insecure_http2_port(s->wrapped, StringValueCStr(port)); if (recvd_port == 0) { rb_raise(rb_eRuntimeError, "could not add port %s to server, not sure why", StringValueCStr(port)); } } else { creds = grpc_rb_get_wrapped_server_credentials(rb_creds); recvd_port = grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port), creds); if (recvd_port == 0) { rb_raise(rb_eRuntimeError, "could not add secure port %s to server, not sure why", StringValueCStr(port)); } } return INT2NUM(recvd_port); } void Init_grpc_server() { grpc_rb_cServer = rb_define_class_under(grpc_rb_mGrpcCore, "Server", rb_cObject); /* Allocates an object managed by the ruby runtime */ rb_define_alloc_func(grpc_rb_cServer, grpc_rb_server_alloc); /* Provides a ruby constructor and support for dup/clone. */ rb_define_method(grpc_rb_cServer, "initialize", grpc_rb_server_init, 2); rb_define_method(grpc_rb_cServer, "initialize_copy", grpc_rb_server_init_copy, 1); /* Add the server methods. */ rb_define_method(grpc_rb_cServer, "request_call", grpc_rb_server_request_call, 3); rb_define_method(grpc_rb_cServer, "start", grpc_rb_server_start, 0); rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, -1); rb_define_alias(grpc_rb_cServer, "close", "destroy"); rb_define_method(grpc_rb_cServer, "add_http2_port", grpc_rb_server_add_http2_port, 2); id_at = rb_intern("at"); id_insecure_server = rb_intern("this_port_is_insecure"); } /* Gets the wrapped server from the ruby wrapper */ grpc_server *grpc_rb_get_wrapped_server(VALUE v) { grpc_rb_server *wrapper = NULL; TypedData_Get_Struct(v, grpc_rb_server, &grpc_rb_server_data_type, wrapper); return wrapper->wrapped; } grpc-0.11.1/src/ruby/ext/grpc/rb_credentials.c0000644000175000017500000002462112600663151021353 0ustar apollockapollock/* * * 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 "rb_credentials.h" #include #include #include #include "rb_grpc.h" /* grpc_rb_cCredentials is the ruby class that proxies grpc_credentials. */ static VALUE grpc_rb_cCredentials = Qnil; /* grpc_rb_credentials wraps a grpc_credentials. It provides a * peer ruby object, 'mark' to minimize copying when a credential is * created from ruby. */ typedef struct grpc_rb_credentials { /* Holder of ruby objects involved in constructing the credentials */ VALUE mark; /* The actual credentials */ grpc_credentials *wrapped; } grpc_rb_credentials; /* Destroys the credentials instances. */ static void grpc_rb_credentials_free(void *p) { grpc_rb_credentials *wrapper = NULL; if (p == NULL) { return; }; wrapper = (grpc_rb_credentials *)p; /* Delete the wrapped object if the mark object is Qnil, which indicates that * no other object is the actual owner. */ if (wrapper->wrapped != NULL && wrapper->mark == Qnil) { grpc_credentials_release(wrapper->wrapped); wrapper->wrapped = NULL; } xfree(p); } /* Protects the mark object from GC */ static void grpc_rb_credentials_mark(void *p) { grpc_rb_credentials *wrapper = NULL; if (p == NULL) { return; } wrapper = (grpc_rb_credentials *)p; /* If it's not already cleaned up, mark the mark object */ if (wrapper->mark != Qnil) { rb_gc_mark(wrapper->mark); } } static rb_data_type_t grpc_rb_credentials_data_type = { "grpc_credentials", {grpc_rb_credentials_mark, grpc_rb_credentials_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY}; /* Allocates Credential instances. Provides safe initial defaults for the instance fields. */ static VALUE grpc_rb_credentials_alloc(VALUE cls) { grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* Clones Credentials instances. Gives Credentials a consistent implementation of Ruby's object copy/dup protocol. */ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) { grpc_rb_credentials *orig_cred = NULL; grpc_rb_credentials *copy_cred = NULL; if (copy == orig) { return copy; } /* Raise an error if orig is not a credentials object or a subclass. */ if (TYPE(orig) != T_DATA || RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_credentials_free) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials)); } TypedData_Get_Struct(orig, grpc_rb_credentials, &grpc_rb_credentials_data_type, orig_cred); TypedData_Get_Struct(copy, grpc_rb_credentials, &grpc_rb_credentials_data_type, copy_cred); /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials * wrapper object. */ MEMCPY(copy_cred, orig_cred, grpc_rb_credentials, 1); return copy; } /* call-seq: creds = Credentials.default() Creates the default credential instances. */ static VALUE grpc_rb_default_credentials_create(VALUE cls) { grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = grpc_google_default_credentials_create(); if (wrapper->wrapped == NULL) { rb_raise(rb_eRuntimeError, "could not create default credentials, not sure why"); return Qnil; } wrapper->mark = Qnil; return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* call-seq: creds = Credentials.compute_engine() Creates the default credential instances. */ static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) { grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = grpc_google_compute_engine_credentials_create(NULL); if (wrapper->wrapped == NULL) { rb_raise(rb_eRuntimeError, "could not create composite engine credentials, not sure why"); return Qnil; } wrapper->mark = Qnil; return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* call-seq: creds1 = ... creds2 = ... creds3 = creds1.add(creds2) Creates the default credential instances. */ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { grpc_rb_credentials *self_wrapper = NULL; grpc_rb_credentials *other_wrapper = NULL; grpc_rb_credentials *wrapper = NULL; TypedData_Get_Struct(self, grpc_rb_credentials, &grpc_rb_credentials_data_type, self_wrapper); TypedData_Get_Struct(other, grpc_rb_credentials, &grpc_rb_credentials_data_type, other_wrapper); wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = grpc_composite_credentials_create( self_wrapper->wrapped, other_wrapper->wrapped, NULL); if (wrapper->wrapped == NULL) { rb_raise(rb_eRuntimeError, "could not create composite credentials, not sure why"); return Qnil; } wrapper->mark = Qnil; return TypedData_Wrap_Struct(grpc_rb_cCredentials, &grpc_rb_credentials_data_type, wrapper); } /* The attribute used on the mark object to hold the pem_root_certs. */ static ID id_pem_root_certs; /* The attribute used on the mark object to hold the pem_private_key. */ static ID id_pem_private_key; /* The attribute used on the mark object to hold the pem_private_key. */ static ID id_pem_cert_chain; /* call-seq: creds1 = Credentials.new(pem_root_certs) ... creds2 = Credentials.new(pem_root_certs, pem_private_key, pem_cert_chain) pem_root_certs: (required) PEM encoding of the server root certificate pem_private_key: (optional) PEM encoding of the client's private key pem_cert_chain: (optional) PEM encoding of the client's cert chain Initializes Credential instances. */ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { VALUE pem_root_certs = Qnil; VALUE pem_private_key = Qnil; VALUE pem_cert_chain = Qnil; grpc_rb_credentials *wrapper = NULL; grpc_credentials *creds = NULL; grpc_ssl_pem_key_cert_pair key_cert_pair; MEMZERO(&key_cert_pair, grpc_ssl_pem_key_cert_pair, 1); /* TODO: Remove mandatory arg when we support default roots. */ /* "12" == 1 mandatory arg, 2 (credentials) is optional */ rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key, &pem_cert_chain); TypedData_Get_Struct(self, grpc_rb_credentials, &grpc_rb_credentials_data_type, wrapper); if (pem_root_certs == Qnil) { rb_raise(rb_eRuntimeError, "could not create a credential: nil pem_root_certs"); return Qnil; } if (pem_private_key == Qnil && pem_cert_chain == Qnil) { creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL, NULL); } else { key_cert_pair.private_key = RSTRING_PTR(pem_private_key); key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), &key_cert_pair, NULL); } if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); return Qnil; } wrapper->wrapped = creds; /* Add the input objects as hidden fields to preserve them. */ rb_ivar_set(self, id_pem_cert_chain, pem_cert_chain); rb_ivar_set(self, id_pem_private_key, pem_private_key); rb_ivar_set(self, id_pem_root_certs, pem_root_certs); return self; } void Init_grpc_credentials() { grpc_rb_cCredentials = rb_define_class_under(grpc_rb_mGrpcCore, "Credentials", rb_cObject); /* Allocates an object managed by the ruby runtime */ rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc); /* Provides a ruby constructor and support for dup/clone. */ rb_define_method(grpc_rb_cCredentials, "initialize", grpc_rb_credentials_init, -1); rb_define_method(grpc_rb_cCredentials, "initialize_copy", grpc_rb_credentials_init_copy, 1); /* Provide static funcs that create new special instances. */ rb_define_singleton_method(grpc_rb_cCredentials, "default", grpc_rb_default_credentials_create, 0); rb_define_singleton_method(grpc_rb_cCredentials, "compute_engine", grpc_rb_compute_engine_credentials_create, 0); /* Provide other methods. */ rb_define_method(grpc_rb_cCredentials, "compose", grpc_rb_composite_credentials_create, 1); id_pem_cert_chain = rb_intern("__pem_cert_chain"); id_pem_private_key = rb_intern("__pem_private_key"); id_pem_root_certs = rb_intern("__pem_root_certs"); } /* Gets the wrapped grpc_credentials from the ruby wrapper */ grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) { grpc_rb_credentials *wrapper = NULL; TypedData_Get_Struct(v, grpc_rb_credentials, &grpc_rb_credentials_data_type, wrapper); return wrapper->wrapped; } grpc-0.11.1/src/ruby/ext/grpc/rb_call.h0000644000175000017500000000433712600663151020000 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_RB_CALL_H_ #define GRPC_RB_CALL_H_ #include #include /* Gets the wrapped call from a VALUE. */ grpc_call* grpc_rb_get_wrapped_call(VALUE v); /* Gets the VALUE corresponding to given grpc_call. */ VALUE grpc_rb_wrap_call(grpc_call* c); /* Provides the details of an call error */ const char* grpc_call_error_detail_of(grpc_call_error err); /* Converts a metadata array to a hash. */ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary); /* grpc_rb_eCallError is the ruby class of the exception thrown during call operations. */ extern VALUE grpc_rb_eCallError; /* Initializes the Call class. */ void Init_grpc_call(); #endif /* GRPC_RB_CALL_H_ */ grpc-0.11.1/src/ruby/ext/grpc/rb_byte_buffer.c0000644000175000017500000000500212600663151021342 0ustar apollockapollock/* * * 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 "rb_byte_buffer.h" #include #include #include #include #include "rb_grpc.h" grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) { gpr_slice slice = gpr_slice_from_copied_buffer(string, length); grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1); gpr_slice_unref(slice); return buffer; } VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) { size_t length = 0; char *string = NULL; size_t offset = 0; grpc_byte_buffer_reader reader; gpr_slice next; if (buffer == NULL) { return Qnil; } length = grpc_byte_buffer_length(buffer); string = xmalloc(length + 1); grpc_byte_buffer_reader_init(&reader, buffer); while (grpc_byte_buffer_reader_next(&reader, &next) != 0) { memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); offset += GPR_SLICE_LENGTH(next); } return rb_str_new(string, length); } grpc-0.11.1/src/ruby/ext/grpc/extconf.rb0000644000175000017500000000722012600663151020216 0ustar apollockapollock# 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. require 'mkmf' LIBDIR = RbConfig::CONFIG['libdir'] INCLUDEDIR = RbConfig::CONFIG['includedir'] HEADER_DIRS = [ # Search /opt/local (Mac source install) '/opt/local/include', # Search /usr/local (Source install) '/usr/local/include', # Check the ruby install locations INCLUDEDIR ] LIB_DIRS = [ # Search /opt/local (Mac source install) '/opt/local/lib', # Search /usr/local (Source install) '/usr/local/lib', # Check the ruby install locations LIBDIR ] def check_grpc_root grpc_root = ENV['GRPC_ROOT'] if grpc_root.nil? r = File.expand_path(File.join(File.dirname(__FILE__), '../../../..')) grpc_root = r if File.exist?(File.join(r, 'include/grpc/grpc.h')) end grpc_root end grpc_pkg_config = system('pkg-config --exists grpc') if grpc_pkg_config $CFLAGS << ' ' + `pkg-config --static --cflags grpc`.strip + ' ' $LDFLAGS << ' ' + `pkg-config --static --libs grpc`.strip + ' ' else dir_config('grpc', HEADER_DIRS, LIB_DIRS) fail 'libdl not found' unless have_library('dl', 'dlopen') fail 'zlib not found' unless have_library('z', 'inflate') begin fail 'Fail' unless have_library('gpr', 'gpr_now') fail 'Fail' unless have_library('grpc', 'grpc_channel_destroy') rescue # Check to see if GRPC_ROOT is defined or available grpc_root = check_grpc_root # Stop if there is still no grpc_root exit 1 if grpc_root.nil? grpc_config = ENV['GRPC_CONFIG'] || 'opt' if ENV.key?('GRPC_LIB_DIR') grpc_lib_dir = File.join(grpc_root, ENV['GRPC_LIB_DIR']) else grpc_lib_dir = File.join(File.join(grpc_root, 'libs'), grpc_config) end unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a')) print "Building internal gRPC\n" system("make -C #{grpc_root} static_c CONFIG=#{grpc_config}") end $CFLAGS << ' -I' + File.join(grpc_root, 'include') $LDFLAGS << ' -L' + grpc_lib_dir raise 'gpr not found' unless have_library('gpr', 'gpr_now') raise 'grpc not found' unless have_library('grpc', 'grpc_channel_destroy') end end $CFLAGS << ' -std=c99 ' $CFLAGS << ' -Wall ' $CFLAGS << ' -Wextra ' $CFLAGS << ' -pedantic ' $CFLAGS << ' -Werror ' create_makefile('grpc/grpc') grpc-0.11.1/src/ruby/ext/grpc/rb_server_credentials.c0000644000175000017500000002451612600663151022744 0ustar apollockapollock/* * * 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 "rb_server_credentials.h" #include #include #include #include "rb_grpc.h" /* grpc_rb_cServerCredentials is the ruby class that proxies grpc_server_credentials. */ static VALUE grpc_rb_cServerCredentials = Qnil; /* grpc_rb_server_credentials wraps a grpc_server_credentials. It provides a peer ruby object, 'mark' to minimize copying when a server credential is created from ruby. */ typedef struct grpc_rb_server_credentials { /* Holder of ruby objects involved in constructing the server credentials */ VALUE mark; /* The actual server credentials */ grpc_server_credentials *wrapped; } grpc_rb_server_credentials; /* Destroys the server credentials instances. */ static void grpc_rb_server_credentials_free(void *p) { grpc_rb_server_credentials *wrapper = NULL; if (p == NULL) { return; }; wrapper = (grpc_rb_server_credentials *)p; /* Delete the wrapped object if the mark object is Qnil, which indicates that no other object is the actual owner. */ if (wrapper->wrapped != NULL && wrapper->mark == Qnil) { grpc_server_credentials_release(wrapper->wrapped); wrapper->wrapped = NULL; } xfree(p); } /* Protects the mark object from GC */ static void grpc_rb_server_credentials_mark(void *p) { grpc_rb_server_credentials *wrapper = NULL; if (p == NULL) { return; } wrapper = (grpc_rb_server_credentials *)p; /* If it's not already cleaned up, mark the mark object */ if (wrapper->mark != Qnil) { rb_gc_mark(wrapper->mark); } } static const rb_data_type_t grpc_rb_server_credentials_data_type = { "grpc_server_credentials", {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY }; /* Allocates ServerCredential instances. Provides safe initial defaults for the instance fields. */ static VALUE grpc_rb_server_credentials_alloc(VALUE cls) { grpc_rb_server_credentials *wrapper = ALLOC(grpc_rb_server_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; return TypedData_Wrap_Struct(cls, &grpc_rb_server_credentials_data_type, wrapper); } /* Clones ServerCredentials instances. Gives ServerCredentials a consistent implementation of Ruby's object copy/dup protocol. */ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) { grpc_rb_server_credentials *orig_ch = NULL; grpc_rb_server_credentials *copy_ch = NULL; if (copy == orig) { return copy; } /* Raise an error if orig is not a server_credentials object or a subclass. */ if (TYPE(orig) != T_DATA || RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_credentials_free) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServerCredentials)); } TypedData_Get_Struct(orig, grpc_rb_server_credentials, &grpc_rb_server_credentials_data_type, orig_ch); TypedData_Get_Struct(copy, grpc_rb_server_credentials, &grpc_rb_server_credentials_data_type, copy_ch); /* use ruby's MEMCPY to make a byte-for-byte copy of the server_credentials wrapper object. */ MEMCPY(copy_ch, orig_ch, grpc_rb_server_credentials, 1); return copy; } /* The attribute used on the mark object to preserve the pem_root_certs. */ static ID id_pem_root_certs; /* The attribute used on the mark object to preserve the pem_key_certs */ static ID id_pem_key_certs; /* The key used to access the pem cert in a key_cert pair hash */ static VALUE sym_cert_chain; /* The key used to access the pem private key in a key_cert pair hash */ static VALUE sym_private_key; /* call-seq: creds = ServerCredentials.new(nil, [{private_key: , {cert_chain: }], force_client_auth) creds = ServerCredentials.new(pem_root_certs, [{private_key: , {cert_chain: }], force_client_auth) pem_root_certs: (optional) PEM encoding of the server root certificate pem_private_key: (required) PEM encoding of the server's private keys force_client_auth: indicatees Initializes ServerCredential instances. */ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, VALUE pem_key_certs, VALUE force_client_auth) { grpc_rb_server_credentials *wrapper = NULL; grpc_server_credentials *creds = NULL; grpc_ssl_pem_key_cert_pair *key_cert_pairs = NULL; VALUE cert = Qnil; VALUE key = Qnil; VALUE key_cert = Qnil; int auth_client = 0; int num_key_certs = 0; int i; if (NIL_P(force_client_auth) || !(force_client_auth == Qfalse || force_client_auth == Qtrue)) { rb_raise(rb_eTypeError, "bad force_client_auth: got:<%s> want: ", rb_obj_classname(force_client_auth)); return Qnil; } if (NIL_P(pem_key_certs) || TYPE(pem_key_certs) != T_ARRAY) { rb_raise(rb_eTypeError, "bad pem_key_certs: got:<%s> want: ", rb_obj_classname(pem_key_certs)); return Qnil; } num_key_certs = RARRAY_LEN(pem_key_certs); if (num_key_certs == 0) { rb_raise(rb_eTypeError, "bad pem_key_certs: it had no elements"); return Qnil; } for (i = 0; i < num_key_certs; i++) { key_cert = rb_ary_entry(pem_key_certs, i); if (key_cert == Qnil) { rb_raise(rb_eTypeError, "could not create a server credential: nil key_cert"); return Qnil; } else if (TYPE(key_cert) != T_HASH) { rb_raise(rb_eTypeError, "could not create a server credential: want , got <%s>", rb_obj_classname(key_cert)); return Qnil; } else if (rb_hash_aref(key_cert, sym_private_key) == Qnil) { rb_raise(rb_eTypeError, "could not create a server credential: want nil private key"); return Qnil; } else if (rb_hash_aref(key_cert, sym_cert_chain) == Qnil) { rb_raise(rb_eTypeError, "could not create a server credential: want nil cert chain"); return Qnil; } } auth_client = TYPE(force_client_auth) == T_TRUE; key_cert_pairs = ALLOC_N(grpc_ssl_pem_key_cert_pair, num_key_certs); for (i = 0; i < num_key_certs; i++) { key_cert = rb_ary_entry(pem_key_certs, i); key = rb_hash_aref(key_cert, sym_private_key); cert = rb_hash_aref(key_cert, sym_cert_chain); key_cert_pairs[i].private_key = RSTRING_PTR(key); key_cert_pairs[i].cert_chain = RSTRING_PTR(cert); } TypedData_Get_Struct(self, grpc_rb_server_credentials, &grpc_rb_server_credentials_data_type, wrapper); if (pem_root_certs == Qnil) { creds = grpc_ssl_server_credentials_create(NULL, key_cert_pairs, num_key_certs, auth_client, NULL); } else { creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs), key_cert_pairs, num_key_certs, auth_client, NULL); } xfree(key_cert_pairs); if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); return Qnil; } wrapper->wrapped = creds; /* Add the input objects as hidden fields to preserve them. */ rb_ivar_set(self, id_pem_key_certs, pem_key_certs); rb_ivar_set(self, id_pem_root_certs, pem_root_certs); return self; } void Init_grpc_server_credentials() { grpc_rb_cServerCredentials = rb_define_class_under(grpc_rb_mGrpcCore, "ServerCredentials", rb_cObject); /* Allocates an object managed by the ruby runtime */ rb_define_alloc_func(grpc_rb_cServerCredentials, grpc_rb_server_credentials_alloc); /* Provides a ruby constructor and support for dup/clone. */ rb_define_method(grpc_rb_cServerCredentials, "initialize", grpc_rb_server_credentials_init, 3); rb_define_method(grpc_rb_cServerCredentials, "initialize_copy", grpc_rb_server_credentials_init_copy, 1); id_pem_key_certs = rb_intern("__pem_key_certs"); id_pem_root_certs = rb_intern("__pem_root_certs"); sym_private_key = ID2SYM(rb_intern("private_key")); sym_cert_chain = ID2SYM(rb_intern("cert_chain")); } /* Gets the wrapped grpc_server_credentials from the ruby wrapper */ grpc_server_credentials *grpc_rb_get_wrapped_server_credentials(VALUE v) { grpc_rb_server_credentials *wrapper = NULL; TypedData_Get_Struct(v, grpc_rb_server_credentials, &grpc_rb_server_credentials_data_type, wrapper); return wrapper->wrapped; } grpc-0.11.1/src/ruby/ext/grpc/rb_server.h0000644000175000017500000000351312600663151020366 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_RB_SERVER_H_ #define GRPC_RB_SERVER_H_ #include #include /* Initializes the Server class. */ void Init_grpc_server(); /* Gets the wrapped server from the ruby wrapper */ grpc_server* grpc_rb_get_wrapped_server(VALUE v); #endif /* GRPC_RB_SERVER_H_ */ grpc-0.11.1/src/ruby/ext/grpc/rb_channel_args.h0000644000175000017500000000434312600663151021506 0ustar apollockapollock/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef GRPC_RB_CHANNEL_ARGS_H_ #define GRPC_RB_CHANNEL_ARGS_H_ #include #include /* Converts a hash object containing channel args to a channel args instance. * * This func ALLOCs args->args. The caller is responsible for freeing it. If * a ruby error is raised during processing of the hash values, the func takes * care to deallocate any memory allocated so far, and propagate the error. * * @param src_hash A ruby hash * @param dst the grpc_channel_args that the hash entries will be added to. */ void grpc_rb_hash_convert_to_channel_args(VALUE src_hash, grpc_channel_args* dst); #endif /* GRPC_RB_CHANNEL_ARGS_H_ */ grpc-0.11.1/src/ruby/ext/grpc/rb_channel.c0000644000175000017500000003530412600663151020466 0ustar apollockapollock/* * * 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 "rb_channel.h" #include #include #include #include #include "rb_grpc.h" #include "rb_call.h" #include "rb_channel_args.h" #include "rb_completion_queue.h" #include "rb_credentials.h" #include "rb_server.h" /* id_channel is the name of the hidden ivar that preserves a reference to the * channel on a call, so that calls are not GCed before their channel. */ static ID id_channel; /* id_target is the name of the hidden ivar that preserves a reference to the * target string used to create the call, preserved so that it does not get * GCed before the channel */ static ID id_target; /* id_cqueue is the name of the hidden ivar that preserves a reference to the * completion queue used to create the call, preserved so that it does not get * GCed before the channel */ static ID id_cqueue; /* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */ static VALUE grpc_rb_cChannel = Qnil; /* Used during the conversion of a hash to channel args during channel setup */ static VALUE grpc_rb_cChannelArgs; /* grpc_rb_channel wraps a grpc_channel. It provides a peer ruby object, * 'mark' to minimize copying when a channel is created from ruby. */ typedef struct grpc_rb_channel { /* Holder of ruby objects involved in constructing the channel */ VALUE mark; /* The actual channel */ grpc_channel *wrapped; } grpc_rb_channel; /* Destroys Channel instances. */ static void grpc_rb_channel_free(void *p) { grpc_rb_channel *ch = NULL; if (p == NULL) { return; }; ch = (grpc_rb_channel *)p; /* Deletes the wrapped object if the mark object is Qnil, which indicates * that no other object is the actual owner. */ if (ch->wrapped != NULL && ch->mark == Qnil) { grpc_channel_destroy(ch->wrapped); rb_warning("channel gc: destroyed the c channel"); } else { rb_warning("channel gc: did not destroy the c channel"); } xfree(p); } /* Protects the mark object from GC */ static void grpc_rb_channel_mark(void *p) { grpc_rb_channel *channel = NULL; if (p == NULL) { return; } channel = (grpc_rb_channel *)p; if (channel->mark != Qnil) { rb_gc_mark(channel->mark); } } static rb_data_type_t grpc_channel_data_type = { "grpc_channel", {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY }; /* Allocates grpc_rb_channel instances. */ static VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); wrapper->wrapped = NULL; wrapper->mark = Qnil; return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); } /* call-seq: insecure_channel = Channel:new("myhost:8080", {'arg1': 'value1'}) creds = ... secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { VALUE channel_args = Qnil; VALUE credentials = Qnil; VALUE target = Qnil; grpc_rb_channel *wrapper = NULL; grpc_credentials *creds = NULL; grpc_channel *ch = NULL; char *target_chars = NULL; grpc_channel_args args; MEMZERO(&args, grpc_channel_args, 1); /* "21" == 2 mandatory args, 1 (credentials) is optional */ rb_scan_args(argc, argv, "21", &target, &channel_args, &credentials); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (credentials == Qnil) { ch = grpc_insecure_channel_create(target_chars, &args, NULL); } else { creds = grpc_rb_get_wrapped_credentials(credentials); ch = grpc_secure_channel_create(creds, target_chars, &args, NULL); } if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ } if (ch == NULL) { rb_raise(rb_eRuntimeError, "could not create an rpc channel to target:%s", target_chars); return Qnil; } rb_ivar_set(self, id_target, target); wrapper->wrapped = ch; return self; } /* call-seq: insecure_channel = Channel:new("myhost:8080", {'arg1': 'value1'}) creds = ... secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, VALUE self) { VALUE try_to_connect = Qfalse; grpc_rb_channel *wrapper = NULL; grpc_channel *ch = NULL; /* "01" == 0 mandatory args, 1 (try_to_connect) is optional */ rb_scan_args(argc, argv, "01", try_to_connect); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } return NUM2LONG( grpc_channel_check_connectivity_state(ch, (int)try_to_connect)); } /* Watch for a change in connectivity state. Once the channel connectivity state is different from the last observed state, tag will be enqueued on cq with success=1 If deadline expires BEFORE the state is changed, tag will be enqueued on the completion queue with success=0 */ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE cqueue, VALUE deadline, VALUE tag) { grpc_rb_channel *wrapper = NULL; grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } grpc_channel_watch_connectivity_state( ch, NUM2LONG(last_state), grpc_rb_time_timeval(deadline, /* absolute time */ 0), cq, ROBJECT(tag)); return Qnil; } /* Clones Channel instances. Gives Channel a consistent implementation of Ruby's object copy/dup protocol. */ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) { grpc_rb_channel *orig_ch = NULL; grpc_rb_channel *copy_ch = NULL; if (copy == orig) { return copy; } /* Raise an error if orig is not a channel object or a subclass. */ if (TYPE(orig) != T_DATA || RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_free) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cChannel)); return Qnil; } TypedData_Get_Struct(orig, grpc_rb_channel, &grpc_channel_data_type, orig_ch); TypedData_Get_Struct(copy, grpc_rb_channel, &grpc_channel_data_type, copy_ch); /* use ruby's MEMCPY to make a byte-for-byte copy of the channel wrapper * object. */ MEMCPY(copy_ch, orig_ch, grpc_rb_channel, 1); return copy; } /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE parent, VALUE mask, VALUE method, VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; grpc_call *parent_call = NULL; grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; int flags = GRPC_PROPAGATE_DEFAULTS; char *method_chars = StringValueCStr(method); char *host_chars = NULL; if (host != Qnil) { host_chars = StringValueCStr(host); } if (mask != Qnil) { flags = NUM2UINT(mask); } if (parent != Qnil) { parent_call = grpc_rb_get_wrapped_call(parent); } cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } call = grpc_channel_create_call(ch, parent_call, flags, cq, method_chars, host_chars, grpc_rb_time_timeval( deadline, /* absolute time */ 0), NULL); if (call == NULL) { rb_raise(rb_eRuntimeError, "cannot create call with method %s", method_chars); return Qnil; } res = grpc_rb_wrap_call(call); /* Make this channel an instance attribute of the call so that it is not GCed * before the call. */ rb_ivar_set(res, id_channel, self); /* Make the completion queue an instance attribute of the call so that it is * not GCed before the call. */ rb_ivar_set(res, id_cqueue, cqueue); return res; } /* Closes the channel, calling it's destroy method */ static VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; grpc_channel *ch = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch != NULL) { grpc_channel_destroy(ch); wrapper->wrapped = NULL; wrapper->mark = Qnil; } return Qnil; } /* Called to obtain the target that this channel accesses. */ static VALUE grpc_rb_channel_get_target(VALUE self) { grpc_rb_channel *wrapper = NULL; VALUE res = Qnil; char* target = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); target = grpc_channel_get_target(wrapper->wrapped); res = rb_str_new2(target); gpr_free(target); return res; } static void Init_grpc_propagate_masks() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mPropagateMasks = rb_define_module_under( grpc_rb_mGrpcCore, "PropagateMasks"); rb_define_const(grpc_rb_mPropagateMasks, "DEADLINE", UINT2NUM(GRPC_PROPAGATE_DEADLINE)); rb_define_const(grpc_rb_mPropagateMasks, "CENSUS_STATS_CONTEXT", UINT2NUM(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT)); rb_define_const(grpc_rb_mPropagateMasks, "CENSUS_TRACING_CONTEXT", UINT2NUM(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT)); rb_define_const(grpc_rb_mPropagateMasks, "CANCELLATION", UINT2NUM(GRPC_PROPAGATE_CANCELLATION)); rb_define_const(grpc_rb_mPropagateMasks, "DEFAULTS", UINT2NUM(GRPC_PROPAGATE_DEFAULTS)); } static void Init_grpc_connectivity_states() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mConnectivityStates = rb_define_module_under( grpc_rb_mGrpcCore, "ConnectivityStates"); rb_define_const(grpc_rb_mConnectivityStates, "IDLE", LONG2NUM(GRPC_CHANNEL_IDLE)); rb_define_const(grpc_rb_mConnectivityStates, "CONNECTING", LONG2NUM(GRPC_CHANNEL_CONNECTING)); rb_define_const(grpc_rb_mConnectivityStates, "READY", LONG2NUM(GRPC_CHANNEL_READY)); rb_define_const(grpc_rb_mConnectivityStates, "TRANSIENT_FAILURE", LONG2NUM(GRPC_CHANNEL_TRANSIENT_FAILURE)); rb_define_const(grpc_rb_mConnectivityStates, "FATAL_FAILURE", LONG2NUM(GRPC_CHANNEL_FATAL_FAILURE)); } void Init_grpc_channel() { grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject); grpc_rb_cChannel = rb_define_class_under(grpc_rb_mGrpcCore, "Channel", rb_cObject); /* Allocates an object managed by the ruby runtime */ rb_define_alloc_func(grpc_rb_cChannel, grpc_rb_channel_alloc); /* Provides a ruby constructor and support for dup/clone. */ rb_define_method(grpc_rb_cChannel, "initialize", grpc_rb_channel_init, -1); rb_define_method(grpc_rb_cChannel, "initialize_copy", grpc_rb_channel_init_copy, 1); /* Add ruby analogues of the Channel methods. */ rb_define_method(grpc_rb_cChannel, "connectivity_state", grpc_rb_channel_get_connectivity_state, -1); rb_define_method(grpc_rb_cChannel, "watch_connectivity_state", grpc_rb_channel_watch_connectivity_state, 4); rb_define_method(grpc_rb_cChannel, "create_call", grpc_rb_channel_create_call, 6); rb_define_method(grpc_rb_cChannel, "target", grpc_rb_channel_get_target, 0); rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0); rb_define_alias(grpc_rb_cChannel, "close", "destroy"); id_channel = rb_intern("__channel"); id_cqueue = rb_intern("__cqueue"); id_target = rb_intern("__target"); rb_define_const(grpc_rb_cChannel, "SSL_TARGET", ID2SYM(rb_intern(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG))); rb_define_const(grpc_rb_cChannel, "ENABLE_CENSUS", ID2SYM(rb_intern(GRPC_ARG_ENABLE_CENSUS))); rb_define_const(grpc_rb_cChannel, "MAX_CONCURRENT_STREAMS", ID2SYM(rb_intern(GRPC_ARG_MAX_CONCURRENT_STREAMS))); rb_define_const(grpc_rb_cChannel, "MAX_MESSAGE_LENGTH", ID2SYM(rb_intern(GRPC_ARG_MAX_MESSAGE_LENGTH))); Init_grpc_propagate_masks(); Init_grpc_connectivity_states(); } /* Gets the wrapped channel from the ruby wrapper */ grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) { grpc_rb_channel *wrapper = NULL; TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper); return wrapper->wrapped; } grpc-0.11.1/src/ruby/ext/grpc/rb_grpc.c0000644000175000017500000002576712600663151020025 0ustar apollockapollock/* * * 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 "rb_grpc.h" #include #include #include #include #include #include #include "rb_call.h" #include "rb_channel.h" #include "rb_completion_queue.h" #include "rb_server.h" #include "rb_credentials.h" #include "rb_server_credentials.h" static VALUE grpc_rb_cTimeVal = Qnil; static rb_data_type_t grpc_rb_timespec_data_type = { "gpr_timespec", {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY}; /* Alloc func that blocks allocation of a given object by raising an * exception. */ VALUE grpc_rb_cannot_alloc(VALUE cls) { rb_raise(rb_eTypeError, "allocation of %s only allowed from the gRPC native layer", rb_class2name(cls)); return Qnil; } /* Init func that fails by raising an exception. */ VALUE grpc_rb_cannot_init(VALUE self) { rb_raise(rb_eTypeError, "initialization of %s only allowed from the gRPC native layer", rb_obj_classname(self)); return Qnil; } /* Init/Clone func that fails by raising an exception. */ VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) { (void)self; rb_raise(rb_eTypeError, "initialization of %s only allowed from the gRPC native layer", rb_obj_classname(copy)); return Qnil; } /* id_tv_{,u}sec are accessor methods on Ruby Time instances. */ static ID id_tv_sec; static ID id_tv_nsec; /** * grpc_rb_time_timeval creates a time_eval from a ruby time object. * * This func is copied from ruby source, MRI/source/time.c, which is published * under the same license as the ruby.h, on which the entire extensions is * based. */ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) { gpr_timespec t; gpr_timespec *time_const; const char *tstr = interval ? "time interval" : "time"; const char *want = " want |