mirror of https://github.com/grpc/grpc.git
commit
43a75af0d0
681 changed files with 29492 additions and 43689 deletions
@ -1,79 +0,0 @@ |
||||
// This file will be moved to a new location. |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
// Labels provide a way to associate user-defined metadata with various |
||||
// objects. Labels may be used to organize objects into non-hierarchical |
||||
// groups; think metadata tags attached to mp3s. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
package tech.label; |
||||
|
||||
// A key-value pair applied to a given object. |
||||
message Label { |
||||
// The key of a label is a syntactically valid URL (as per RFC 1738) with |
||||
// the "scheme" and initial slashes omitted and with the additional |
||||
// restrictions noted below. Each key should be globally unique. The |
||||
// "host" portion is called the "namespace" and is not necessarily |
||||
// resolvable to a network endpoint. Instead, the namespace indicates what |
||||
// system or entity defines the semantics of the label. Namespaces do not |
||||
// restrict the set of objects to which a label may be associated. |
||||
// |
||||
// Keys are defined by the following grammar: |
||||
// |
||||
// key = hostname "/" kpath |
||||
// kpath = ksegment *[ "/" ksegment ] |
||||
// ksegment = alphadigit | *[ alphadigit | "-" | "_" | "." ] |
||||
// |
||||
// where "hostname" and "alphadigit" are defined as in RFC 1738. |
||||
// |
||||
// Example key: |
||||
// spanner.google.com/universe |
||||
required string key = 1; |
||||
|
||||
// The value of the label. |
||||
oneof value { |
||||
// A string value. |
||||
string str_value = 2; |
||||
// An integer value. |
||||
int64 num_value = 3; |
||||
} |
||||
} |
||||
|
||||
// A collection of labels, such as the set of all labels attached to an |
||||
// object. Each label in the set must have a different key. |
||||
// |
||||
// Users should prefer to embed "repeated Label" directly when possible. |
||||
// This message should only be used in cases where that isn't possible (e.g. |
||||
// with oneof). |
||||
message Labels { |
||||
repeated Label label = 1; |
||||
} |
@ -1,729 +0,0 @@ |
||||
// This file will be moved to a new location. |
||||
|
||||
// Copyright 2015, Google Inc. |
||||
// All rights reserved. |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
|
||||
// Specification of the Pubsub API. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
import "examples/pubsub/empty.proto"; |
||||
import "examples/pubsub/label.proto"; |
||||
|
||||
package tech.pubsub; |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// Overview of the Pubsub API |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// This file describes an API for a Pubsub system. This system provides a |
||||
// reliable many-to-many communication mechanism between independently written |
||||
// publishers and subscribers where the publisher publishes messages to "topics" |
||||
// and each subscriber creates a "subscription" and consumes messages from it. |
||||
// |
||||
// (a) The pubsub system maintains bindings between topics and subscriptions. |
||||
// (b) A publisher publishes messages into a topic. |
||||
// (c) The pubsub system delivers messages from topics into relevant |
||||
// subscriptions. |
||||
// (d) A subscriber receives pending messages from its subscription and |
||||
// acknowledges or nacks each one to the pubsub system. |
||||
// (e) The pubsub system removes acknowledged messages from that subscription. |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// Data Model |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// The data model consists of the following: |
||||
// |
||||
// * Topic: A topic is a resource to which messages are published by publishers. |
||||
// Topics are named, and the name of the topic is unique within the pubsub |
||||
// system. |
||||
// |
||||
// * Subscription: A subscription records the subscriber's interest in a topic. |
||||
// It can optionally include a query to select a subset of interesting |
||||
// messages. The pubsub system maintains a logical cursor tracking the |
||||
// matching messages which still need to be delivered and acked so that |
||||
// they can retried as needed. The set of messages that have not been |
||||
// acknowledged is called the subscription backlog. |
||||
// |
||||
// * Message: A message is a unit of data that flows in the system. It contains |
||||
// opaque data from the publisher along with its labels. |
||||
// |
||||
// * Message Labels (optional): A set of opaque key, value pairs assigned |
||||
// by the publisher which the subscriber can use for filtering out messages |
||||
// in the topic. For example, a label with key "foo.com/device_type" and |
||||
// value "mobile" may be added for messages that are only relevant for a |
||||
// mobile subscriber; a subscriber on a phone may decide to create a |
||||
// subscription only for messages that have this label. |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// Publisher Flow |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// A publisher publishes messages to the topic using the Publish request: |
||||
// |
||||
// PubsubMessage message; |
||||
// message.set_data("...."); |
||||
// Label label; |
||||
// label.set_key("foo.com/key1"); |
||||
// label.set_str_value("value1"); |
||||
// message.add_label(label); |
||||
// PublishRequest request; |
||||
// request.set_topic("topicName"); |
||||
// request.set_message(message); |
||||
// PublisherService.Publish(request); |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// Subscriber Flow |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// The subscriber part of the API is richer than the publisher part and has a |
||||
// number of concepts w.r.t. subscription creation and monitoring: |
||||
// |
||||
// (1) A subscriber creates a subscription using the CreateSubscription call. |
||||
// It may specify an optional "query" to indicate that it wants to receive |
||||
// only messages with a certain set of labels using the label query syntax. |
||||
// It may also specify an optional truncation policy to indicate when old |
||||
// messages from the subcription can be removed. |
||||
// |
||||
// (2) A subscriber receives messages in one of two ways: via push or pull. |
||||
// |
||||
// (a) To receive messages via push, the PushConfig field must be specified in |
||||
// the Subscription parameter when creating a subscription. The PushConfig |
||||
// specifies an endpoint at which the subscriber must expose the |
||||
// PushEndpointService. Messages are received via the HandlePubsubEvent |
||||
// method. The push subscriber responds to the HandlePubsubEvent method |
||||
// with a result code that indicates one of three things: Ack (the message |
||||
// has been successfully processed and the Pubsub system may delete it), |
||||
// Nack (the message has been rejected, the Pubsub system should resend it |
||||
// at a later time), or Push-Back (this is a Nack with the additional |
||||
// semantics that the subscriber is overloaded and the pubsub system should |
||||
// back off on the rate at which it is invoking HandlePubsubEvent). The |
||||
// endpoint may be a load balancer for better scalability. |
||||
// |
||||
// (b) To receive messages via pull a subscriber calls the Pull method on the |
||||
// SubscriberService to get messages from the subscription. For each |
||||
// individual message, the subscriber may use the ack_id received in the |
||||
// PullResponse to Ack the message, Nack the message, or modify the ack |
||||
// deadline with ModifyAckDeadline. See the |
||||
// Subscription.ack_deadline_seconds field documentation for details on the |
||||
// ack deadline behavior. |
||||
// |
||||
// Note: Messages may be consumed in parallel by multiple subscribers making |
||||
// Pull calls to the same subscription; this will result in the set of |
||||
// messages from the subscription being shared and each subscriber |
||||
// receiving a subset of the messages. |
||||
// |
||||
// (4) The subscriber can explicitly truncate the current subscription. |
||||
// |
||||
// (5) "Truncated" events are delivered when a subscription is |
||||
// truncated, whether due to the subscription's truncation policy |
||||
// or an explicit request from the subscriber. |
||||
// |
||||
// Subscription creation: |
||||
// |
||||
// Subscription subscription; |
||||
// subscription.set_topic("topicName"); |
||||
// subscription.set_name("subscriptionName"); |
||||
// subscription.push_config().set_push_endpoint("machinename:8888"); |
||||
// SubscriberService.CreateSubscription(subscription); |
||||
// |
||||
// Consuming messages via push: |
||||
// |
||||
// The port 'machinename:8888' must be bound to a server that implements |
||||
// the PushEndpointService with the following method: |
||||
// |
||||
// int HandlePubsubEvent(PubsubEvent event) { |
||||
// if (event.subscription().equals("subscriptionName")) { |
||||
// if (event.has_message()) { |
||||
// Process(event.message().data()); |
||||
// } else if (event.truncated()) { |
||||
// ProcessTruncatedEvent(); |
||||
// } |
||||
// } |
||||
// return OK; // This return code implies an acknowledgment |
||||
// } |
||||
// |
||||
// Consuming messages via pull: |
||||
// |
||||
// The subscription must be created without setting the push_config field. |
||||
// |
||||
// PullRequest pull_request; |
||||
// pull_request.set_subscription("subscriptionName"); |
||||
// pull_request.set_return_immediately(false); |
||||
// while (true) { |
||||
// PullResponse pull_response; |
||||
// if (SubscriberService.Pull(pull_request, pull_response) == OK) { |
||||
// PubsubEvent event = pull_response.pubsub_event(); |
||||
// if (event.has_message()) { |
||||
// Process(event.message().data()); |
||||
// } else if (event.truncated()) { |
||||
// ProcessTruncatedEvent(); |
||||
// } |
||||
// AcknowledgeRequest ack_request; |
||||
// ackRequest.set_subscription("subscriptionName"); |
||||
// ackRequest.set_ack_id(pull_response.ack_id()); |
||||
// SubscriberService.Acknowledge(ack_request); |
||||
// } |
||||
// } |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// Reliability Semantics |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// When a subscriber successfully creates a subscription using |
||||
// Subscriber.CreateSubscription, it establishes a "subscription point" with |
||||
// respect to that subscription - the subscriber is guaranteed to receive any |
||||
// message published after this subscription point that matches the |
||||
// subscription's query. Note that messages published before the Subscription |
||||
// point may or may not be delivered. |
||||
// |
||||
// If the system truncates the subscription according to the specified |
||||
// truncation policy, the system delivers a subscription status event with the |
||||
// "truncated" field set to true. We refer to such events as "truncation |
||||
// events". A truncation event: |
||||
// |
||||
// * Informs the subscriber that part of the subscription messages have been |
||||
// discarded. The subscriber may want to recover from the message loss, e.g., |
||||
// by resyncing its state with its backend. |
||||
// * Establishes a new subscription point, i.e., the subscriber is guaranteed to |
||||
// receive all changes published after the trunction event is received (or |
||||
// until another truncation event is received). |
||||
// |
||||
// Note that messages are not delivered in any particular order by the pubsub |
||||
// system. Furthermore, the system guarantees at-least-once delivery |
||||
// of each message or truncation events until acked. |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// Deletion |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// Both topics and subscriptions may be deleted. Deletion of a topic implies |
||||
// deletion of all attached subscriptions. |
||||
// |
||||
// When a subscription is deleted directly by calling DeleteSubscription, all |
||||
// messages are immediately dropped. If it is a pull subscriber, future pull |
||||
// requests will return NOT_FOUND. |
||||
// |
||||
// When a topic is deleted all corresponding subscriptions are immediately |
||||
// deleted, and subscribers experience the same behavior as directly deleting |
||||
// the subscription. |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// The Publisher service and its protos. |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// The service that an application uses to manipulate topics, and to send |
||||
// messages to a topic. |
||||
service PublisherService { |
||||
|
||||
// Creates the given topic with the given name. |
||||
rpc CreateTopic(Topic) returns (Topic) { |
||||
} |
||||
|
||||
// Adds a message to the topic. Returns NOT_FOUND if the topic does not |
||||
// exist. |
||||
rpc Publish(PublishRequest) returns (proto2.Empty) { |
||||
} |
||||
|
||||
// Adds one or more messages to the topic. Returns NOT_FOUND if the topic does |
||||
// not exist. |
||||
rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse) { |
||||
} |
||||
|
||||
// Gets the configuration of a topic. Since the topic only has the name |
||||
// attribute, this method is only useful to check the existence of a topic. |
||||
// If other attributes are added in the future, they will be returned here. |
||||
rpc GetTopic(GetTopicRequest) returns (Topic) { |
||||
} |
||||
|
||||
// Lists matching topics. |
||||
rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse) { |
||||
} |
||||
|
||||
// Deletes the topic with the given name. All subscriptions to this topic |
||||
// are also deleted. Returns NOT_FOUND if the topic does not exist. |
||||
// After a topic is deleted, a new topic may be created with the same name. |
||||
rpc DeleteTopic(DeleteTopicRequest) returns (proto2.Empty) { |
||||
} |
||||
} |
||||
|
||||
// A topic resource. |
||||
message Topic { |
||||
// Name of the topic. |
||||
optional string name = 1; |
||||
} |
||||
|
||||
// A message data and its labels. |
||||
message PubsubMessage { |
||||
// The message payload. |
||||
optional bytes data = 1; |
||||
|
||||
// Optional list of labels for this message. Keys in this collection must |
||||
// be unique. |
||||
repeated tech.label.Label label = 2; |
||||
|
||||
// ID of this message assigned by the server at publication time. Guaranteed |
||||
// to be unique within the topic. This value may be read by a subscriber |
||||
// that receives a PubsubMessage via a Pull call or a push delivery. It must |
||||
// not be populated by a publisher in a Publish call. |
||||
optional string message_id = 3; |
||||
} |
||||
|
||||
// Request for the GetTopic method. |
||||
message GetTopicRequest { |
||||
// The name of the topic to get. |
||||
optional string topic = 1; |
||||
} |
||||
|
||||
// Request for the Publish method. |
||||
message PublishRequest { |
||||
// The message in the request will be published on this topic. |
||||
optional string topic = 1; |
||||
|
||||
// The message to publish. |
||||
optional PubsubMessage message = 2; |
||||
} |
||||
|
||||
// Request for the PublishBatch method. |
||||
message PublishBatchRequest { |
||||
// The messages in the request will be published on this topic. |
||||
optional string topic = 1; |
||||
|
||||
// The messages to publish. |
||||
repeated PubsubMessage messages = 2; |
||||
} |
||||
|
||||
// Response for the PublishBatch method. |
||||
message PublishBatchResponse { |
||||
// The server-assigned ID of each published message, in the same order as |
||||
// the messages in the request. IDs are guaranteed to be unique within |
||||
// the topic. |
||||
repeated string message_ids = 1; |
||||
} |
||||
|
||||
// Request for the ListTopics method. |
||||
message ListTopicsRequest { |
||||
// A valid label query expression. |
||||
// (-- Which labels are required or supported is implementation-specific. --) |
||||
optional string query = 1; |
||||
|
||||
// Maximum number of topics to return. |
||||
// (-- If not specified or <= 0, the implementation will select a reasonable |
||||
// value. --) |
||||
optional int32 max_results = 2; |
||||
|
||||
// The value obtained in the last <code>ListTopicsResponse</code> |
||||
// for continuation. |
||||
optional string page_token = 3; |
||||
|
||||
} |
||||
|
||||
// Response for the ListTopics method. |
||||
message ListTopicsResponse { |
||||
// The resulting topics. |
||||
repeated Topic topic = 1; |
||||
|
||||
// If not empty, indicates that there are more topics that match the request, |
||||
// and this value should be passed to the next <code>ListTopicsRequest</code> |
||||
// to continue. |
||||
optional string next_page_token = 2; |
||||
} |
||||
|
||||
// Request for the Delete method. |
||||
message DeleteTopicRequest { |
||||
// Name of the topic to delete. |
||||
optional string topic = 1; |
||||
} |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// The Subscriber service and its protos. |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// The service that an application uses to manipulate subscriptions and to |
||||
// consume messages from a subscription via the pull method. |
||||
service SubscriberService { |
||||
|
||||
// Creates a subscription on a given topic for a given subscriber. |
||||
// If the subscription already exists, returns ALREADY_EXISTS. |
||||
// If the corresponding topic doesn't exist, returns NOT_FOUND. |
||||
// |
||||
// If the name is not provided in the request, the server will assign a random |
||||
// name for this subscription on the same project as the topic. |
||||
rpc CreateSubscription(Subscription) returns (Subscription) { |
||||
} |
||||
|
||||
// Gets the configuration details of a subscription. |
||||
rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) { |
||||
} |
||||
|
||||
// Lists matching subscriptions. |
||||
rpc ListSubscriptions(ListSubscriptionsRequest) |
||||
returns (ListSubscriptionsResponse) { |
||||
} |
||||
|
||||
// Deletes an existing subscription. All pending messages in the subscription |
||||
// are immediately dropped. Calls to Pull after deletion will return |
||||
// NOT_FOUND. |
||||
rpc DeleteSubscription(DeleteSubscriptionRequest) returns (proto2.Empty) { |
||||
} |
||||
|
||||
// Removes all the pending messages in the subscription and releases the |
||||
// storage associated with them. Results in a truncation event to be sent to |
||||
// the subscriber. Messages added after this call returns are stored in the |
||||
// subscription as before. |
||||
rpc TruncateSubscription(TruncateSubscriptionRequest) returns (proto2.Empty) { |
||||
} |
||||
|
||||
// |
||||
// Push subscriber calls. |
||||
// |
||||
|
||||
// Modifies the <code>PushConfig</code> for a specified subscription. |
||||
// This method can be used to suspend the flow of messages to an endpoint |
||||
// by clearing the <code>PushConfig</code> field in the request. Messages |
||||
// will be accumulated for delivery even if no push configuration is |
||||
// defined or while the configuration is modified. |
||||
rpc ModifyPushConfig(ModifyPushConfigRequest) returns (proto2.Empty) { |
||||
} |
||||
|
||||
// |
||||
// Pull Subscriber calls |
||||
// |
||||
|
||||
// Pulls a single message from the server. |
||||
// If return_immediately is true, and no messages are available in the |
||||
// subscription, this method returns FAILED_PRECONDITION. The system is free |
||||
// to return an UNAVAILABLE error if no messages are available in a |
||||
// reasonable amount of time (to reduce system load). |
||||
rpc Pull(PullRequest) returns (PullResponse) { |
||||
} |
||||
|
||||
// Pulls messages from the server. Returns an empty list if there are no |
||||
// messages available in the backlog. The system is free to return UNAVAILABLE |
||||
// if there are too many pull requests outstanding for the given subscription. |
||||
rpc PullBatch(PullBatchRequest) returns (PullBatchResponse) { |
||||
} |
||||
|
||||
// Modifies the Ack deadline for a message received from a pull request. |
||||
rpc ModifyAckDeadline(ModifyAckDeadlineRequest) returns (proto2.Empty) { |
||||
} |
||||
|
||||
// Acknowledges a particular received message: the Pub/Sub system can remove |
||||
// the given message from the subscription. Acknowledging a message whose |
||||
// Ack deadline has expired may succeed, but the message could have been |
||||
// already redelivered. Acknowledging a message more than once will not |
||||
// result in an error. This is only used for messages received via pull. |
||||
rpc Acknowledge(AcknowledgeRequest) returns (proto2.Empty) { |
||||
} |
||||
|
||||
// Refuses processing a particular received message. The system will |
||||
// redeliver this message to some consumer of the subscription at some |
||||
// future time. This is only used for messages received via pull. |
||||
rpc Nack(NackRequest) returns (proto2.Empty) { |
||||
} |
||||
} |
||||
|
||||
// A subscription resource. |
||||
message Subscription { |
||||
// Name of the subscription. |
||||
optional string name = 1; |
||||
|
||||
// The name of the topic from which this subscription is receiving messages. |
||||
optional string topic = 2; |
||||
|
||||
// If <code>query</code> is non-empty, only messages on the subscriber's |
||||
// topic whose labels match the query will be returned. Otherwise all |
||||
// messages on the topic will be returned. |
||||
// (-- The query syntax is described in label_query.proto --) |
||||
optional string query = 3; |
||||
|
||||
// The subscriber may specify requirements for truncating unacknowledged |
||||
// subscription entries. The system will honor the |
||||
// <code>CreateSubscription</code> request only if it can meet these |
||||
// requirements. If this field is not specified, messages are never truncated |
||||
// by the system. |
||||
optional TruncationPolicy truncation_policy = 4; |
||||
|
||||
// Specifies which messages can be truncated by the system. |
||||
message TruncationPolicy { |
||||
oneof policy { |
||||
// If <code>max_bytes</code> is specified, the system is allowed to drop |
||||
// old messages to keep the combined size of stored messages under |
||||
// <code>max_bytes</code>. This is a hint; the system may keep more than |
||||
// this many bytes, but will make a best effort to keep the size from |
||||
// growing much beyond this parameter. |
||||
int64 max_bytes = 1; |
||||
|
||||
// If <code>max_age_seconds</code> is specified, the system is allowed to |
||||
// drop messages that have been stored for at least this many seconds. |
||||
// This is a hint; the system may keep these messages, but will make a |
||||
// best effort to remove them when their maximum age is reached. |
||||
int64 max_age_seconds = 2; |
||||
} |
||||
} |
||||
|
||||
// If push delivery is used with this subscription, this field is |
||||
// used to configure it. |
||||
optional PushConfig push_config = 5; |
||||
|
||||
// For either push or pull delivery, the value is the maximum time after a |
||||
// subscriber receives a message before the subscriber should acknowledge or |
||||
// Nack the message. If the Ack deadline for a message passes without an |
||||
// Ack or a Nack, the Pub/Sub system will eventually redeliver the message. |
||||
// If a subscriber acknowledges after the deadline, the Pub/Sub system may |
||||
// accept the Ack, but it is possible that the message has been already |
||||
// delivered again. Multiple Acks to the message are allowed and will |
||||
// succeed. |
||||
// |
||||
// For push delivery, this value is used to set the request timeout for |
||||
// the call to the push endpoint. |
||||
// |
||||
// For pull delivery, this value is used as the initial value for the Ack |
||||
// deadline. It may be overridden for a specific pull request (message) with |
||||
// <code>ModifyAckDeadline</code>. |
||||
// While a message is outstanding (i.e. it has been delivered to a pull |
||||
// subscriber and the subscriber has not yet Acked or Nacked), the Pub/Sub |
||||
// system will not deliver that message to another pull subscriber |
||||
// (on a best-effort basis). |
||||
optional int32 ack_deadline_seconds = 6; |
||||
|
||||
// If this parameter is set to n, the system is allowed to (but not required |
||||
// to) delete the subscription when at least n seconds have elapsed since the |
||||
// client presence was detected. (Presence is detected through any |
||||
// interaction using the subscription ID, including Pull(), Get(), or |
||||
// acknowledging a message.) |
||||
// |
||||
// If this parameter is not set, the subscription will stay live until |
||||
// explicitly deleted. |
||||
// |
||||
// Clients can detect such garbage collection when a Get call or a Pull call |
||||
// (for pull subscribers only) returns NOT_FOUND. |
||||
optional int64 garbage_collect_seconds = 7; |
||||
} |
||||
|
||||
// Configuration for a push delivery endpoint. |
||||
message PushConfig { |
||||
// A URL locating the endpoint to which messages should be pushed. |
||||
// For example, a Webhook endpoint might use "https://example.com/push". |
||||
// (-- An Android application might use "gcm:<REGID>", where <REGID> is a |
||||
// GCM registration id allocated for pushing messages to the application. --) |
||||
optional string push_endpoint = 1; |
||||
} |
||||
|
||||
// An event indicating a received message or truncation event. |
||||
message PubsubEvent { |
||||
// The subscription that received the event. |
||||
optional string subscription = 1; |
||||
|
||||
oneof type { |
||||
// A received message. |
||||
PubsubMessage message = 2; |
||||
|
||||
// Indicates that this subscription has been truncated. |
||||
bool truncated = 3; |
||||
|
||||
// Indicates that this subscription has been deleted. (Note that pull |
||||
// subscribers will always receive NOT_FOUND in response in their pull |
||||
// request on the subscription, rather than seeing this boolean.) |
||||
bool deleted = 4; |
||||
} |
||||
} |
||||
|
||||
// Request for the GetSubscription method. |
||||
message GetSubscriptionRequest { |
||||
// The name of the subscription to get. |
||||
optional string subscription = 1; |
||||
} |
||||
|
||||
// Request for the ListSubscriptions method. |
||||
message ListSubscriptionsRequest { |
||||
// A valid label query expression. |
||||
// (-- Which labels are required or supported is implementation-specific. |
||||
// TODO(eschapira): This method must support to query by topic. We must |
||||
// define the key URI for the "topic" label. --) |
||||
optional string query = 1; |
||||
|
||||
// Maximum number of subscriptions to return. |
||||
// (-- If not specified or <= 0, the implementation will select a reasonable |
||||
// value. --) |
||||
optional int32 max_results = 3; |
||||
|
||||
// The value obtained in the last <code>ListSubscriptionsResponse</code> |
||||
// for continuation. |
||||
optional string page_token = 4; |
||||
} |
||||
|
||||
// Response for the ListSubscriptions method. |
||||
message ListSubscriptionsResponse { |
||||
// The subscriptions that match the request. |
||||
repeated Subscription subscription = 1; |
||||
|
||||
// If not empty, indicates that there are more subscriptions that match the |
||||
// request and this value should be passed to the next |
||||
// <code>ListSubscriptionsRequest</code> to continue. |
||||
optional string next_page_token = 2; |
||||
} |
||||
|
||||
// Request for the TruncateSubscription method. |
||||
message TruncateSubscriptionRequest { |
||||
// The subscription that is being truncated. |
||||
optional string subscription = 1; |
||||
} |
||||
|
||||
// Request for the DeleteSubscription method. |
||||
message DeleteSubscriptionRequest { |
||||
// The subscription to delete. |
||||
optional string subscription = 1; |
||||
} |
||||
|
||||
// Request for the ModifyPushConfig method. |
||||
message ModifyPushConfigRequest { |
||||
// The name of the subscription. |
||||
optional string subscription = 1; |
||||
|
||||
// An empty <code>push_config</code> indicates that the Pub/Sub system should |
||||
// pause pushing messages from the given subscription. |
||||
optional PushConfig push_config = 2; |
||||
} |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// The protos used by a pull subscriber. |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// Request for the Pull method. |
||||
message PullRequest { |
||||
// The subscription from which a message should be pulled. |
||||
optional string subscription = 1; |
||||
|
||||
// If this is specified as true the system will respond immediately even if |
||||
// it is not able to return a message in the Pull response. Otherwise the |
||||
// system is allowed to wait until at least one message is available rather |
||||
// than returning FAILED_PRECONDITION. The client may cancel the request if |
||||
// it does not wish to wait any longer for the response. |
||||
optional bool return_immediately = 2; |
||||
} |
||||
|
||||
// Either a <code>PubsubMessage</code> or a truncation event. One of these two |
||||
// must be populated. |
||||
message PullResponse { |
||||
// This ID must be used to acknowledge the received event or message. |
||||
optional string ack_id = 1; |
||||
|
||||
// A pubsub message or truncation event. |
||||
optional PubsubEvent pubsub_event = 2; |
||||
} |
||||
|
||||
// Request for the PullBatch method. |
||||
message PullBatchRequest { |
||||
// The subscription from which messages should be pulled. |
||||
optional string subscription = 1; |
||||
|
||||
// If this is specified as true the system will respond immediately even if |
||||
// it is not able to return a message in the Pull response. Otherwise the |
||||
// system is allowed to wait until at least one message is available rather |
||||
// than returning no messages. The client may cancel the request if it does |
||||
// not wish to wait any longer for the response. |
||||
optional bool return_immediately = 2; |
||||
|
||||
// The maximum number of PubsubEvents returned for this request. The Pub/Sub |
||||
// system may return fewer than the number of events specified. |
||||
optional int32 max_events = 3; |
||||
} |
||||
|
||||
// Response for the PullBatch method. |
||||
message PullBatchResponse { |
||||
|
||||
// Received Pub/Sub messages or status events. The Pub/Sub system will return |
||||
// zero messages if there are no more messages available in the backlog. The |
||||
// Pub/Sub system may return fewer than the max_events requested even if |
||||
// there are more messages available in the backlog. |
||||
repeated PullResponse pull_responses = 2; |
||||
} |
||||
|
||||
// Request for the ModifyAckDeadline method. |
||||
message ModifyAckDeadlineRequest { |
||||
// The name of the subscription from which messages are being pulled. |
||||
optional string subscription = 1; |
||||
|
||||
// The acknowledgment ID. |
||||
optional string ack_id = 2; |
||||
|
||||
// The new Ack deadline. Must be >= 0. |
||||
optional int32 ack_deadline_seconds = 3; |
||||
} |
||||
|
||||
// Request for the Acknowledge method. |
||||
message AcknowledgeRequest { |
||||
// The subscription whose message is being acknowledged. |
||||
optional string subscription = 1; |
||||
|
||||
// The acknowledgment ID for the message being acknowledged. This was |
||||
// returned by the Pub/Sub system in the Pull response. |
||||
repeated string ack_id = 2; |
||||
} |
||||
|
||||
// Request for the Nack method. |
||||
message NackRequest { |
||||
// The subscription whose message is being Nacked. |
||||
optional string subscription = 1; |
||||
|
||||
// The acknowledgment ID for the message being refused. This was returned by |
||||
// the Pub/Sub system in the Pull response. |
||||
repeated string ack_id = 2; |
||||
} |
||||
|
||||
// ----------------------------------------------------------------------------- |
||||
// The service and protos used by a push subscriber. |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// The service that a subscriber uses to handle messages sent via push |
||||
// delivery. |
||||
// This service is not currently exported for HTTP clients. |
||||
// TODO(eschapira): Explain HTTP subscribers. |
||||
service PushEndpointService { |
||||
// Sends a <code>PubsubMessage</code> or a subscription status event to a |
||||
// push endpoint. |
||||
// The push endpoint responds with an empty message and a code from |
||||
// util/task/codes.proto. The following codes have a particular meaning to the |
||||
// Pub/Sub system: |
||||
// OK - This is interpreted by Pub/Sub as Ack. |
||||
// ABORTED - This is intepreted by Pub/Sub as a Nack, without implying |
||||
// pushback for congestion control. The Pub/Sub system will |
||||
// retry this message at a later time. |
||||
// UNAVAILABLE - This is intepreted by Pub/Sub as a Nack, with the additional |
||||
// semantics of push-back. The Pub/Sub system will use an AIMD |
||||
// congestion control algorithm to backoff the rate of sending |
||||
// messages from this subscription. |
||||
// Any other code, or a failure to respond, will be interpreted in the same |
||||
// way as ABORTED; i.e. the system will retry the message at a later time to |
||||
// ensure reliable delivery. |
||||
rpc HandlePubsubEvent(PubsubEvent) returns (proto2.Empty); |
||||
} |
@ -0,0 +1,94 @@ |
||||
Pod::Spec.new do |s| |
||||
s.name = 'gRPC' |
||||
s.version = '0.0.1' |
||||
s.summary = 'Generic gRPC client library for iOS' |
||||
s.homepage = 'https://www.grpc.io' |
||||
s.license = 'New BSD' |
||||
s.authors = { 'Jorge Canizales' => 'jcanizales@google.com', |
||||
'Michael Lumish' => 'mlumish@google.com' } |
||||
|
||||
# s.source = { :git => 'https://github.com/grpc/grpc.git', :tag => 'release-0_5_0' } |
||||
|
||||
s.platform = :ios |
||||
s.ios.deployment_target = '6.0' |
||||
s.requires_arc = true |
||||
|
||||
s.subspec 'RxLibrary' do |rs| |
||||
rs.summary = 'Reactive Extensions library for iOS.' |
||||
rs.authors = { 'Jorge Canizales' => 'jcanizales@google.com' } |
||||
|
||||
rs.source_files = 'src/objective-c/RxLibrary/*.{h,m}', |
||||
'src/objective-c/RxLibrary/transformations/*.{h,m}', |
||||
'src/objective-c/RxLibrary/private/*.{h,m}' |
||||
rs.private_header_files = 'src/objective-c/RxLibrary/private/*.h' |
||||
end |
||||
|
||||
s.subspec 'C-Core' do |cs| |
||||
cs.summary = 'Core cross-platform gRPC library, written in C.' |
||||
cs.authors = { 'Craig Tiller' => 'ctiller@google.com', |
||||
'David Klempner' => 'klempner@google.com', |
||||
'Nicolas Noble' => 'nnoble@google.com', |
||||
'Vijay Pai' => 'vpai@google.com', |
||||
'Yang Gao' => 'yangg@google.com' } |
||||
|
||||
cs.source_files = 'src/core/**/*.{h,c}', 'include/grpc/*.h', 'include/grpc/**/*.h' |
||||
cs.private_header_files = 'src/core/**/*.h' |
||||
cs.header_mappings_dir = '.' |
||||
cs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Build/gRPC" "$(PODS_ROOT)/Headers/Build/gRPC/include"' } |
||||
|
||||
cs.requires_arc = false |
||||
cs.libraries = 'z' |
||||
cs.dependency 'OpenSSL', '~> 1.0.200' |
||||
end |
||||
|
||||
# This is a workaround for Cocoapods Issue #1437. |
||||
# It renames time.h and string.h to grpc_time.h and grpc_string.h. |
||||
# It needs to be here (top-level) instead of in the C-Core subspec because Cocoapods doesn't run |
||||
# prepare_command's of subspecs. |
||||
s.prepare_command = <<-CMD |
||||
DIR_TIME="grpc/support" |
||||
BAD_TIME="$DIR_TIME/time.h" |
||||
GOOD_TIME="$DIR_TIME/grpc_time.h" |
||||
if [ -f "include/$BAD_TIME" ]; |
||||
then |
||||
grep -rl "$BAD_TIME" include/grpc src/core | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g |
||||
mv "include/$BAD_TIME" "include/$GOOD_TIME" |
||||
fi |
||||
|
||||
DIR_STRING="src/core/support" |
||||
BAD_STRING="$DIR_STRING/string.h" |
||||
GOOD_STRING="$DIR_STRING/grpc_string.h" |
||||
if [ -f "$BAD_STRING" ]; |
||||
then |
||||
grep -rl "$BAD_STRING" include/grpc src/core | xargs sed -i '' -e s@$BAD_STRING@$GOOD_STRING@g |
||||
mv "$BAD_STRING" "$GOOD_STRING" |
||||
fi |
||||
CMD |
||||
|
||||
s.subspec 'GRPCClient' do |gs| |
||||
gs.summary = 'Objective-C wrapper around the core gRPC library.' |
||||
gs.authors = { 'Jorge Canizales' => 'jcanizales@google.com' } |
||||
|
||||
gs.source_files = 'src/objective-c/GRPCClient/*.{h,m}', |
||||
'src/objective-c/GRPCClient/private/*.{h,m}' |
||||
gs.private_header_files = 'src/objective-c/GRPCClient/private/*.h' |
||||
|
||||
gs.dependency 'gRPC/C-Core' |
||||
# Is this needed in all dependents? |
||||
gs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Public/gRPC/include"' } |
||||
gs.dependency 'gRPC/RxLibrary' |
||||
|
||||
# Certificates, to be able to establish TLS connections: |
||||
gs.resource_bundles = { 'gRPC' => ['etc/roots.pem'] } |
||||
end |
||||
|
||||
s.subspec 'ProtoRPC' do |ps| |
||||
ps.summary = 'RPC library for ProtocolBuffers, based on gRPC' |
||||
ps.authors = { 'Jorge Canizales' => 'jcanizales@google.com' } |
||||
|
||||
ps.source_files = 'src/objective-c/ProtoRPC/*.{h,m}' |
||||
|
||||
ps.dependency 'gRPC/GRPCClient' |
||||
ps.dependency 'gRPC/RxLibrary' |
||||
end |
||||
end |
@ -0,0 +1,106 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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 GRPCXX_TIME_H |
||||
#define GRPCXX_TIME_H |
||||
|
||||
#include <grpc++/config.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
/* If you are trying to use CompletionQueue::AsyncNext with a time class that
|
||||
isn't either gpr_timespec or std::chrono::system_clock::time_point, you |
||||
will most likely be looking at this comment as your compiler will have |
||||
fired an error below. In order to fix this issue, you have two potential |
||||
solutions: |
||||
|
||||
1. Use gpr_timespec or std::chrono::system_clock::time_point instead |
||||
2. Specialize the TimePoint class with whichever time class that you |
||||
want to use here. See below for two examples of how to do this. |
||||
*/ |
||||
|
||||
template <typename T> |
||||
class TimePoint { |
||||
public: |
||||
TimePoint(const T& time) { |
||||
you_need_a_specialization_of_TimePoint(); |
||||
} |
||||
gpr_timespec raw_time() { |
||||
gpr_timespec t; |
||||
return t; |
||||
} |
||||
private: |
||||
void you_need_a_specialization_of_TimePoint(); |
||||
}; |
||||
|
||||
template<> |
||||
class TimePoint<gpr_timespec> { |
||||
public: |
||||
TimePoint(const gpr_timespec& time) : time_(time) { } |
||||
gpr_timespec raw_time() { return time_; } |
||||
private: |
||||
gpr_timespec time_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#ifndef GRPC_CXX0X_NO_CHRONO |
||||
|
||||
#include <chrono> |
||||
|
||||
#include <grpc/support/time.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
// from and to should be absolute time.
|
||||
void Timepoint2Timespec(const std::chrono::system_clock::time_point& from, |
||||
gpr_timespec* to); |
||||
|
||||
std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t); |
||||
|
||||
template <> |
||||
class TimePoint<std::chrono::system_clock::time_point> { |
||||
public: |
||||
TimePoint(const std::chrono::system_clock::time_point& time) { |
||||
Timepoint2Timespec(time, &time_); |
||||
} |
||||
gpr_timespec raw_time() const { return time_; } |
||||
private: |
||||
gpr_timespec time_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // !GRPC_CXX0X_NO_CHRONO
|
||||
|
||||
#endif // GRPCXX_TIME_H
|
@ -0,0 +1,480 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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 <cctype> |
||||
#include <map> |
||||
#include <vector> |
||||
|
||||
#include "src/compiler/config.h" |
||||
#include "src/compiler/csharp_generator_helpers.h" |
||||
#include "src/compiler/csharp_generator.h" |
||||
|
||||
using grpc::protobuf::FileDescriptor; |
||||
using grpc::protobuf::Descriptor; |
||||
using grpc::protobuf::ServiceDescriptor; |
||||
using grpc::protobuf::MethodDescriptor; |
||||
using grpc::protobuf::io::Printer; |
||||
using grpc::protobuf::io::StringOutputStream; |
||||
using grpc_generator::MethodType; |
||||
using grpc_generator::GetMethodType; |
||||
using grpc_generator::METHODTYPE_NO_STREAMING; |
||||
using grpc_generator::METHODTYPE_CLIENT_STREAMING; |
||||
using grpc_generator::METHODTYPE_SERVER_STREAMING; |
||||
using grpc_generator::METHODTYPE_BIDI_STREAMING; |
||||
using std::map; |
||||
using std::vector; |
||||
|
||||
namespace grpc_csharp_generator { |
||||
namespace { |
||||
|
||||
std::string GetCSharpNamespace(const FileDescriptor* file) { |
||||
// TODO(jtattermusch): this should be based on csharp_namespace option
|
||||
return file->package(); |
||||
} |
||||
|
||||
std::string GetMessageType(const Descriptor* message) { |
||||
// TODO(jtattermusch): this has to match with C# protobuf generator
|
||||
return message->name(); |
||||
} |
||||
|
||||
std::string GetServiceClassName(const ServiceDescriptor* service) { |
||||
return service->name(); |
||||
} |
||||
|
||||
std::string GetClientInterfaceName(const ServiceDescriptor* service) { |
||||
return "I" + service->name() + "Client"; |
||||
} |
||||
|
||||
std::string GetClientClassName(const ServiceDescriptor* service) { |
||||
return service->name() + "Client"; |
||||
} |
||||
|
||||
std::string GetServerInterfaceName(const ServiceDescriptor* service) { |
||||
return "I" + service->name(); |
||||
} |
||||
|
||||
std::string GetCSharpMethodType(MethodType method_type) { |
||||
switch (method_type) { |
||||
case METHODTYPE_NO_STREAMING: |
||||
return "MethodType.Unary"; |
||||
case METHODTYPE_CLIENT_STREAMING: |
||||
return "MethodType.ClientStreaming"; |
||||
case METHODTYPE_SERVER_STREAMING: |
||||
return "MethodType.ServerStreaming"; |
||||
case METHODTYPE_BIDI_STREAMING: |
||||
return "MethodType.DuplexStreaming"; |
||||
} |
||||
GOOGLE_LOG(FATAL)<< "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
std::string GetServiceNameFieldName() { |
||||
return "__ServiceName"; |
||||
} |
||||
|
||||
std::string GetMarshallerFieldName(const Descriptor *message) { |
||||
return "__Marshaller_" + message->name(); |
||||
} |
||||
|
||||
std::string GetMethodFieldName(const MethodDescriptor *method) { |
||||
return "__Method_" + method->name(); |
||||
} |
||||
|
||||
std::string GetMethodRequestParamMaybe(const MethodDescriptor *method) { |
||||
if (method->client_streaming()) { |
||||
return ""; |
||||
} |
||||
return GetMessageType(method->input_type()) + " request, "; |
||||
} |
||||
|
||||
std::string GetMethodReturnTypeClient(const MethodDescriptor *method) { |
||||
switch (GetMethodType(method)) { |
||||
case METHODTYPE_NO_STREAMING: |
||||
return "Task<" + GetMessageType(method->output_type()) + ">"; |
||||
case METHODTYPE_CLIENT_STREAMING: |
||||
return "AsyncClientStreamingCall<" + GetMessageType(method->input_type()) |
||||
+ ", " + GetMessageType(method->output_type()) + ">"; |
||||
case METHODTYPE_SERVER_STREAMING: |
||||
return "AsyncServerStreamingCall<" + GetMessageType(method->output_type()) |
||||
+ ">"; |
||||
case METHODTYPE_BIDI_STREAMING: |
||||
return "AsyncDuplexStreamingCall<" + GetMessageType(method->input_type()) |
||||
+ ", " + GetMessageType(method->output_type()) + ">"; |
||||
} |
||||
GOOGLE_LOG(FATAL)<< "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
std::string GetMethodRequestParamServer(const MethodDescriptor *method) { |
||||
switch (GetMethodType(method)) { |
||||
case METHODTYPE_NO_STREAMING: |
||||
case METHODTYPE_SERVER_STREAMING: |
||||
return GetMessageType(method->input_type()) + " request"; |
||||
case METHODTYPE_CLIENT_STREAMING: |
||||
case METHODTYPE_BIDI_STREAMING: |
||||
return "IAsyncStreamReader<" + GetMessageType(method->input_type()) |
||||
+ "> requestStream"; |
||||
} |
||||
GOOGLE_LOG(FATAL)<< "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
std::string GetMethodReturnTypeServer(const MethodDescriptor *method) { |
||||
switch (GetMethodType(method)) { |
||||
case METHODTYPE_NO_STREAMING: |
||||
case METHODTYPE_CLIENT_STREAMING: |
||||
return "Task<" + GetMessageType(method->output_type()) + ">"; |
||||
case METHODTYPE_SERVER_STREAMING: |
||||
case METHODTYPE_BIDI_STREAMING: |
||||
return "Task"; |
||||
} |
||||
GOOGLE_LOG(FATAL)<< "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
std::string GetMethodResponseStreamMaybe(const MethodDescriptor *method) { |
||||
switch (GetMethodType(method)) { |
||||
case METHODTYPE_NO_STREAMING: |
||||
case METHODTYPE_CLIENT_STREAMING: |
||||
return ""; |
||||
case METHODTYPE_SERVER_STREAMING: |
||||
case METHODTYPE_BIDI_STREAMING: |
||||
return ", IServerStreamWriter<" + GetMessageType(method->output_type()) |
||||
+ "> responseStream"; |
||||
} |
||||
GOOGLE_LOG(FATAL)<< "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
// Gets vector of all messages used as input or output types.
|
||||
std::vector<const Descriptor*> GetUsedMessages( |
||||
const ServiceDescriptor *service) { |
||||
std::set<const Descriptor*> descriptor_set; |
||||
std::vector<const Descriptor*> result; // vector is to maintain stable ordering
|
||||
for (int i = 0; i < service->method_count(); i++) { |
||||
const MethodDescriptor *method = service->method(i); |
||||
if (descriptor_set.find(method->input_type()) == descriptor_set.end()) { |
||||
descriptor_set.insert(method->input_type()); |
||||
result.push_back(method->input_type()); |
||||
} |
||||
if (descriptor_set.find(method->output_type()) == descriptor_set.end()) { |
||||
descriptor_set.insert(method->output_type()); |
||||
result.push_back(method->output_type()); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
void GenerateMarshallerFields(Printer* out, const ServiceDescriptor *service) { |
||||
std::vector<const Descriptor*> used_messages = GetUsedMessages(service); |
||||
for (size_t i = 0; i < used_messages.size(); i++) { |
||||
const Descriptor *message = used_messages[i]; |
||||
out->Print( |
||||
"static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => arg.ToByteArray(), $type$.ParseFrom);\n", |
||||
"fieldname", GetMarshallerFieldName(message), "type", |
||||
GetMessageType(message)); |
||||
} |
||||
out->Print("\n"); |
||||
} |
||||
|
||||
void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) { |
||||
out->Print( |
||||
"static readonly Method<$request$, $response$> $fieldname$ = new Method<$request$, $response$>(\n", |
||||
"fieldname", GetMethodFieldName(method), "request", |
||||
GetMessageType(method->input_type()), "response", |
||||
GetMessageType(method->output_type())); |
||||
out->Indent(); |
||||
out->Indent(); |
||||
out->Print("$methodtype$,\n", "methodtype", |
||||
GetCSharpMethodType(GetMethodType(method))); |
||||
out->Print("\"$methodname$\",\n", "methodname", method->name()); |
||||
out->Print("$requestmarshaller$,\n", "requestmarshaller", |
||||
GetMarshallerFieldName(method->input_type())); |
||||
out->Print("$responsemarshaller$);\n", "responsemarshaller", |
||||
GetMarshallerFieldName(method->output_type())); |
||||
out->Print("\n"); |
||||
out->Outdent(); |
||||
out->Outdent(); |
||||
} |
||||
|
||||
void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) { |
||||
out->Print("// client-side stub interface\n"); |
||||
out->Print("public interface $name$\n", "name", |
||||
GetClientInterfaceName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
for (int i = 0; i < service->method_count(); i++) { |
||||
const MethodDescriptor *method = service->method(i); |
||||
MethodType method_type = GetMethodType(method); |
||||
|
||||
if (method_type == METHODTYPE_NO_STREAMING) { |
||||
// unary calls have an extra synchronous stub method
|
||||
out->Print( |
||||
"$response$ $methodname$($request$ request, CancellationToken token = default(CancellationToken));\n", |
||||
"methodname", method->name(), "request", |
||||
GetMessageType(method->input_type()), "response", |
||||
GetMessageType(method->output_type())); |
||||
} |
||||
|
||||
std::string method_name = method->name(); |
||||
if (method_type == METHODTYPE_NO_STREAMING) { |
||||
method_name += "Async"; // prevent name clash with synchronous method.
|
||||
} |
||||
out->Print( |
||||
"$returntype$ $methodname$($request_maybe$CancellationToken token = default(CancellationToken));\n", |
||||
"methodname", method_name, "request_maybe", |
||||
GetMethodRequestParamMaybe(method), "returntype", |
||||
GetMethodReturnTypeClient(method)); |
||||
} |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
out->Print("\n"); |
||||
} |
||||
|
||||
void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) { |
||||
out->Print("// server-side interface\n"); |
||||
out->Print("public interface $name$\n", "name", |
||||
GetServerInterfaceName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
for (int i = 0; i < service->method_count(); i++) { |
||||
const MethodDescriptor *method = service->method(i); |
||||
out->Print("$returntype$ $methodname$(ServerCallContext context, $request$$response_stream_maybe$);\n", |
||||
"methodname", method->name(), "returntype", |
||||
GetMethodReturnTypeServer(method), "request", |
||||
GetMethodRequestParamServer(method), "response_stream_maybe", |
||||
GetMethodResponseStreamMaybe(method)); |
||||
} |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
out->Print("\n"); |
||||
} |
||||
|
||||
void GenerateClientStub(Printer* out, const ServiceDescriptor *service) { |
||||
out->Print("// client stub\n"); |
||||
out->Print( |
||||
"public class $name$ : AbstractStub<$name$, StubConfiguration>, $interface$\n", |
||||
"name", GetClientClassName(service), "interface", |
||||
GetClientInterfaceName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
|
||||
// constructors
|
||||
out->Print( |
||||
"public $name$(Channel channel) : this(channel, StubConfiguration.Default)\n", |
||||
"name", GetClientClassName(service)); |
||||
out->Print("{\n"); |
||||
out->Print("}\n"); |
||||
out->Print( |
||||
"public $name$(Channel channel, StubConfiguration config) : base(channel, config)\n", |
||||
"name", GetClientClassName(service)); |
||||
out->Print("{\n"); |
||||
out->Print("}\n"); |
||||
|
||||
for (int i = 0; i < service->method_count(); i++) { |
||||
const MethodDescriptor *method = service->method(i); |
||||
MethodType method_type = GetMethodType(method); |
||||
|
||||
if (method_type == METHODTYPE_NO_STREAMING) { |
||||
// unary calls have an extra synchronous stub method
|
||||
out->Print( |
||||
"public $response$ $methodname$($request$ request, CancellationToken token = default(CancellationToken))\n", |
||||
"methodname", method->name(), "request", |
||||
GetMessageType(method->input_type()), "response", |
||||
GetMessageType(method->output_type())); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
out->Print("var call = CreateCall($servicenamefield$, $methodfield$);\n", |
||||
"servicenamefield", GetServiceNameFieldName(), "methodfield", |
||||
GetMethodFieldName(method)); |
||||
out->Print("return Calls.BlockingUnaryCall(call, request, token);\n"); |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
} |
||||
|
||||
std::string method_name = method->name(); |
||||
if (method_type == METHODTYPE_NO_STREAMING) { |
||||
method_name += "Async"; // prevent name clash with synchronous method.
|
||||
} |
||||
out->Print( |
||||
"public $returntype$ $methodname$($request_maybe$CancellationToken token = default(CancellationToken))\n", |
||||
"methodname", method_name, "request_maybe", |
||||
GetMethodRequestParamMaybe(method), "returntype", |
||||
GetMethodReturnTypeClient(method)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
out->Print("var call = CreateCall($servicenamefield$, $methodfield$);\n", |
||||
"servicenamefield", GetServiceNameFieldName(), "methodfield", |
||||
GetMethodFieldName(method)); |
||||
switch (GetMethodType(method)) { |
||||
case METHODTYPE_NO_STREAMING: |
||||
out->Print("return Calls.AsyncUnaryCall(call, request, token);\n"); |
||||
break; |
||||
case METHODTYPE_CLIENT_STREAMING: |
||||
out->Print("return Calls.AsyncClientStreamingCall(call, token);\n"); |
||||
break; |
||||
case METHODTYPE_SERVER_STREAMING: |
||||
out->Print( |
||||
"return Calls.AsyncServerStreamingCall(call, request, token);\n"); |
||||
break; |
||||
case METHODTYPE_BIDI_STREAMING: |
||||
out->Print("return Calls.AsyncDuplexStreamingCall(call, token);\n"); |
||||
break; |
||||
default: |
||||
GOOGLE_LOG(FATAL)<< "Can't get here."; |
||||
} |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
} |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
out->Print("\n"); |
||||
} |
||||
|
||||
void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service) { |
||||
out->Print( |
||||
"// creates service definition that can be registered with a server\n"); |
||||
out->Print( |
||||
"public static ServerServiceDefinition BindService($interface$ serviceImpl)\n", |
||||
"interface", GetServerInterfaceName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
|
||||
out->Print( |
||||
"return ServerServiceDefinition.CreateBuilder($servicenamefield$)\n", |
||||
"servicenamefield", GetServiceNameFieldName()); |
||||
out->Indent(); |
||||
out->Indent(); |
||||
for (int i = 0; i < service->method_count(); i++) { |
||||
const MethodDescriptor *method = service->method(i); |
||||
out->Print(".AddMethod($methodfield$, serviceImpl.$methodname$)", |
||||
"methodfield", GetMethodFieldName(method), "methodname", |
||||
method->name()); |
||||
if (i == service->method_count() - 1) { |
||||
out->Print(".Build();"); |
||||
} |
||||
out->Print("\n"); |
||||
} |
||||
out->Outdent(); |
||||
out->Outdent(); |
||||
|
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
out->Print("\n"); |
||||
} |
||||
|
||||
void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) { |
||||
out->Print("// creates a new client stub\n"); |
||||
out->Print("public static $interface$ NewStub(Channel channel)\n", |
||||
"interface", GetClientInterfaceName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
out->Print("return new $classname$(channel);\n", "classname", |
||||
GetClientClassName(service)); |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
out->Print("\n"); |
||||
|
||||
out->Print("// creates a new client stub\n"); |
||||
out->Print( |
||||
"public static $interface$ NewStub(Channel channel, StubConfiguration config)\n", |
||||
"interface", GetClientInterfaceName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
out->Print("return new $classname$(channel, config);\n", "classname", |
||||
GetClientClassName(service)); |
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
} |
||||
|
||||
void GenerateService(Printer* out, const ServiceDescriptor *service) { |
||||
out->Print("public static class $classname$\n", "classname", |
||||
GetServiceClassName(service)); |
||||
out->Print("{\n"); |
||||
out->Indent(); |
||||
out->Print("static readonly string $servicenamefield$ = \"$servicename$\";\n", |
||||
"servicenamefield", GetServiceNameFieldName(), "servicename", |
||||
service->full_name()); |
||||
out->Print("\n"); |
||||
|
||||
GenerateMarshallerFields(out, service); |
||||
for (int i = 0; i < service->method_count(); i++) { |
||||
GenerateStaticMethodField(out, service->method(i)); |
||||
} |
||||
GenerateClientInterface(out, service); |
||||
GenerateServerInterface(out, service); |
||||
GenerateClientStub(out, service); |
||||
GenerateBindServiceMethod(out, service); |
||||
GenerateNewStubMethods(out, service); |
||||
|
||||
out->Outdent(); |
||||
out->Print("}\n"); |
||||
} |
||||
|
||||
} // anonymous namespace
|
||||
|
||||
grpc::string GetServices(const FileDescriptor *file) { |
||||
grpc::string output; |
||||
StringOutputStream output_stream(&output); |
||||
Printer out(&output_stream, '$'); |
||||
|
||||
// Don't write out any output if there no services, to avoid empty service
|
||||
// files being generated for proto files that don't declare any.
|
||||
if (file->service_count() == 0) { |
||||
return output; |
||||
} |
||||
|
||||
// Write out a file header.
|
||||
out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n"); |
||||
out.Print("// source: $filename$\n", "filename", file->name()); |
||||
out.Print("#region Designer generated code\n"); |
||||
out.Print("\n"); |
||||
out.Print("using System;\n"); |
||||
out.Print("using System.Threading;\n"); |
||||
out.Print("using System.Threading.Tasks;\n"); |
||||
out.Print("using Grpc.Core;\n"); |
||||
// TODO(jtattermusch): add using for protobuf message classes
|
||||
out.Print("\n"); |
||||
|
||||
out.Print("namespace $namespace$ {\n", "namespace", GetCSharpNamespace(file)); |
||||
out.Indent(); |
||||
for (int i = 0; i < file->service_count(); i++) { |
||||
GenerateService(&out, file->service(i)); |
||||
} |
||||
out.Outdent(); |
||||
out.Print("}\n"); |
||||
out.Print("#endregion\n"); |
||||
return output; |
||||
} |
||||
|
||||
} // namespace grpc_csharp_generator
|
@ -0,0 +1,45 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_H |
||||
#define GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_H |
||||
|
||||
#include "src/compiler/config.h" |
||||
|
||||
namespace grpc_csharp_generator { |
||||
|
||||
grpc::string GetServices(const grpc::protobuf::FileDescriptor *file); |
||||
|
||||
} // namespace grpc_csharp_generator
|
||||
|
||||
#endif // GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_H
|
@ -0,0 +1,50 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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_COMPILER_CSHARP_GENERATOR_HELPERS_H |
||||
#define GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_HELPERS_H |
||||
|
||||
#include "src/compiler/config.h" |
||||
#include "src/compiler/generator_helpers.h" |
||||
|
||||
namespace grpc_csharp_generator { |
||||
|
||||
inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file, |
||||
grpc::string *file_name_or_error) { |
||||
*file_name_or_error = grpc_generator::FileNameInUpperCamel(file) + "Grpc.cs"; |
||||
return true; |
||||
} |
||||
|
||||
} // namespace grpc_csharp_generator
|
||||
|
||||
#endif // GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_HELPERS_H
|
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
// Generates C# gRPC service interface out of Protobuf IDL.
|
||||
|
||||
#include <memory> |
||||
|
||||
#include "src/compiler/config.h" |
||||
#include "src/compiler/csharp_generator.h" |
||||
#include "src/compiler/csharp_generator_helpers.h" |
||||
|
||||
class CSharpGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { |
||||
public: |
||||
CSharpGrpcGenerator() {} |
||||
~CSharpGrpcGenerator() {} |
||||
|
||||
bool Generate(const grpc::protobuf::FileDescriptor *file, |
||||
const grpc::string ¶meter, |
||||
grpc::protobuf::compiler::GeneratorContext *context, |
||||
grpc::string *error) const { |
||||
grpc::string code = grpc_csharp_generator::GetServices(file); |
||||
if (code.size() == 0) { |
||||
return true; // don't generate a file if there are no services
|
||||
} |
||||
|
||||
// Get output file name.
|
||||
grpc::string file_name; |
||||
if (!grpc_csharp_generator::ServicesFilename(file, &file_name)) { |
||||
return false; |
||||
} |
||||
std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output( |
||||
context->Open(file_name)); |
||||
grpc::protobuf::io::CodedOutputStream coded_out(output.get()); |
||||
coded_out.WriteRaw(code.data(), code.size()); |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
CSharpGrpcGenerator generator; |
||||
return grpc::protobuf::compiler::PluginMain(argc, argv, &generator); |
||||
} |
@ -1,134 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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 <stdarg.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include "src/core/support/string.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { |
||||
gpr_strvec_add(b, gpr_strdup(" key=")); |
||||
gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), |
||||
GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT)); |
||||
|
||||
gpr_strvec_add(b, gpr_strdup(" value=")); |
||||
gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice), |
||||
GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT)); |
||||
} |
||||
|
||||
char *grpc_call_op_string(grpc_call_op *op) { |
||||
char *tmp; |
||||
char *out; |
||||
|
||||
gpr_strvec b; |
||||
gpr_strvec_init(&b); |
||||
|
||||
switch (op->dir) { |
||||
case GRPC_CALL_DOWN: |
||||
gpr_strvec_add(&b, gpr_strdup(">")); |
||||
break; |
||||
case GRPC_CALL_UP: |
||||
gpr_strvec_add(&b, gpr_strdup("<")); |
||||
break; |
||||
} |
||||
switch (op->type) { |
||||
case GRPC_SEND_METADATA: |
||||
gpr_strvec_add(&b, gpr_strdup("SEND_METADATA")); |
||||
put_metadata(&b, op->data.metadata); |
||||
break; |
||||
case GRPC_SEND_DEADLINE: |
||||
gpr_asprintf(&tmp, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec, |
||||
op->data.deadline.tv_nsec); |
||||
gpr_strvec_add(&b, tmp); |
||||
break; |
||||
case GRPC_SEND_START: |
||||
gpr_asprintf(&tmp, "SEND_START pollset=%p", op->data.start.pollset); |
||||
gpr_strvec_add(&b, tmp); |
||||
break; |
||||
case GRPC_SEND_MESSAGE: |
||||
gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE")); |
||||
break; |
||||
case GRPC_SEND_PREFORMATTED_MESSAGE: |
||||
gpr_strvec_add(&b, gpr_strdup("SEND_PREFORMATTED_MESSAGE")); |
||||
break; |
||||
case GRPC_SEND_FINISH: |
||||
gpr_strvec_add(&b, gpr_strdup("SEND_FINISH")); |
||||
break; |
||||
case GRPC_REQUEST_DATA: |
||||
gpr_strvec_add(&b, gpr_strdup("REQUEST_DATA")); |
||||
break; |
||||
case GRPC_RECV_METADATA: |
||||
gpr_strvec_add(&b, gpr_strdup("RECV_METADATA")); |
||||
put_metadata(&b, op->data.metadata); |
||||
break; |
||||
case GRPC_RECV_DEADLINE: |
||||
gpr_asprintf(&tmp, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec, |
||||
op->data.deadline.tv_nsec); |
||||
gpr_strvec_add(&b, tmp); |
||||
break; |
||||
case GRPC_RECV_END_OF_INITIAL_METADATA: |
||||
gpr_strvec_add(&b, gpr_strdup("RECV_END_OF_INITIAL_METADATA")); |
||||
break; |
||||
case GRPC_RECV_MESSAGE: |
||||
gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); |
||||
break; |
||||
case GRPC_RECV_HALF_CLOSE: |
||||
gpr_strvec_add(&b, gpr_strdup("RECV_HALF_CLOSE")); |
||||
break; |
||||
case GRPC_RECV_FINISH: |
||||
gpr_strvec_add(&b, gpr_strdup("RECV_FINISH")); |
||||
break; |
||||
case GRPC_CANCEL_OP: |
||||
gpr_strvec_add(&b, gpr_strdup("CANCEL_OP")); |
||||
break; |
||||
} |
||||
gpr_asprintf(&tmp, " flags=0x%08x", op->flags); |
||||
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_call_op *op) { |
||||
char *str = grpc_call_op_string(op); |
||||
gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); |
||||
gpr_free(str); |
||||
} |
@ -1,137 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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_filter.h" |
||||
#include <grpc/support/log.h> |
||||
|
||||
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) {} |
||||
|
||||
/* 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 call_op(grpc_call_element *elem, grpc_call_element *from_elem, |
||||
grpc_call_op *op) { |
||||
/* grab pointers to our data from the call element */ |
||||
call_data *calld = elem->call_data; |
||||
channel_data *channeld = elem->channel_data; |
||||
GRPC_CALL_LOG_OP(GPR_INFO, elem, op); |
||||
|
||||
ignore_unused(calld); |
||||
ignore_unused(channeld); |
||||
|
||||
switch (op->type) { |
||||
default: |
||||
/* pass control up or down the stack depending on op->dir */ |
||||
grpc_call_next_op(elem, op); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Called on special channel events, such as disconnection or new incoming
|
||||
calls on the server */ |
||||
static void channel_op(grpc_channel_element *elem, |
||||
grpc_channel_element *from_elem, grpc_channel_op *op) { |
||||
/* grab pointers to our data from the channel element */ |
||||
channel_data *channeld = elem->channel_data; |
||||
|
||||
ignore_unused(channeld); |
||||
|
||||
switch (op->type) { |
||||
default: |
||||
/* pass control up or down the stack depending on op->dir */ |
||||
grpc_channel_next_op(elem, op); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Constructor for call_data */ |
||||
static void init_call_elem(grpc_call_element *elem, |
||||
const void *server_transport_data) { |
||||
/* 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; |
||||
} |
||||
|
||||
/* 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, |
||||
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_http_filter = { |
||||
call_op, channel_op, sizeof(call_data), |
||||
init_call_elem, destroy_call_elem, sizeof(channel_data), |
||||
init_channel_elem, destroy_channel_elem, "http"}; |
@ -1,149 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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/metadata_buffer.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#define INITIAL_ELEM_CAP 8 |
||||
|
||||
/* One queued call; we track offsets to string data in a shared buffer to
|
||||
reduce allocations. See grpc_metadata_buffer_impl for the memory use |
||||
strategy */ |
||||
typedef struct { |
||||
grpc_mdelem *md; |
||||
void (*cb)(void *user_data, grpc_op_error error); |
||||
void *user_data; |
||||
gpr_uint32 flags; |
||||
} qelem; |
||||
|
||||
/* Memory layout:
|
||||
|
||||
grpc_metadata_buffer_impl |
||||
followed by an array of qelem */ |
||||
struct grpc_metadata_buffer_impl { |
||||
/* number of elements in q */ |
||||
size_t elems; |
||||
/* capacity of q */ |
||||
size_t elem_cap; |
||||
}; |
||||
|
||||
#define ELEMS(buffer) ((qelem *)((buffer) + 1)) |
||||
|
||||
void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer) { |
||||
/* start buffer as NULL, indicating no elements */ |
||||
*buffer = NULL; |
||||
} |
||||
|
||||
void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer, |
||||
grpc_op_error error) { |
||||
size_t i; |
||||
qelem *qe; |
||||
if (*buffer) { |
||||
for (i = 0; i < (*buffer)->elems; i++) { |
||||
qe = &ELEMS(*buffer)[i]; |
||||
grpc_mdelem_unref(qe->md); |
||||
qe->cb(qe->user_data, error); |
||||
} |
||||
gpr_free(*buffer); |
||||
} |
||||
} |
||||
|
||||
void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, |
||||
grpc_call_op *op) { |
||||
grpc_metadata_buffer_impl *impl = *buffer; |
||||
qelem *qe; |
||||
size_t bytes; |
||||
|
||||
GPR_ASSERT(op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA); |
||||
|
||||
if (!impl) { |
||||
/* this is the first element: allocate enough space to hold the
|
||||
header object and the initial element capacity of qelems */ |
||||
bytes = |
||||
sizeof(grpc_metadata_buffer_impl) + INITIAL_ELEM_CAP * sizeof(qelem); |
||||
impl = gpr_malloc(bytes); |
||||
/* initialize the header object */ |
||||
impl->elems = 0; |
||||
impl->elem_cap = INITIAL_ELEM_CAP; |
||||
} else if (impl->elems == impl->elem_cap) { |
||||
/* more qelems than what we can deal with: grow by doubling size */ |
||||
impl->elem_cap *= 2; |
||||
bytes = sizeof(grpc_metadata_buffer_impl) + impl->elem_cap * sizeof(qelem); |
||||
impl = gpr_realloc(impl, bytes); |
||||
} |
||||
|
||||
/* append an element to the queue */ |
||||
qe = &ELEMS(impl)[impl->elems]; |
||||
impl->elems++; |
||||
|
||||
qe->md = op->data.metadata; |
||||
qe->cb = op->done_cb; |
||||
qe->user_data = op->user_data; |
||||
qe->flags = op->flags; |
||||
|
||||
/* header object may have changed location: store it back */ |
||||
*buffer = impl; |
||||
} |
||||
|
||||
void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer, |
||||
grpc_call_element *elem) { |
||||
grpc_metadata_buffer_impl *impl = *buffer; |
||||
grpc_call_op op; |
||||
qelem *qe; |
||||
size_t i; |
||||
|
||||
if (!impl) { |
||||
/* nothing to send */ |
||||
return; |
||||
} |
||||
|
||||
/* construct call_op's, and push them down the stack */ |
||||
op.type = GRPC_SEND_METADATA; |
||||
op.dir = GRPC_CALL_DOWN; |
||||
for (i = 0; i < impl->elems; i++) { |
||||
qe = &ELEMS(impl)[i]; |
||||
op.done_cb = qe->cb; |
||||
op.user_data = qe->user_data; |
||||
op.flags = qe->flags; |
||||
op.data.metadata = qe->md; |
||||
grpc_call_next_op(elem, &op); |
||||
} |
||||
|
||||
/* free data structures and reset to NULL: we can only flush once */ |
||||
gpr_free(impl); |
||||
*buffer = NULL; |
||||
} |
@ -1,70 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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_METADATA_BUFFER_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H |
||||
|
||||
#include "src/core/channel/channel_stack.h" |
||||
|
||||
/* Utility code to buffer GRPC_SEND_METADATA calls and pass them down the stack
|
||||
all at once at some otherwise-determined time. Useful for implementing |
||||
filters that want to queue metadata until a START event chooses some |
||||
underlying filter stack to send an rpc on. */ |
||||
|
||||
/* Clients should declare a member of grpc_metadata_buffer. This may at some
|
||||
point become a typedef for a struct, but for now a pointer suffices */ |
||||
typedef struct grpc_metadata_buffer_impl grpc_metadata_buffer_impl; |
||||
typedef grpc_metadata_buffer_impl *grpc_metadata_buffer; |
||||
|
||||
/* Initializes the metadata buffer. Allocates no memory. */ |
||||
void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer); |
||||
/* Destroy the metadata buffer. */ |
||||
void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer, |
||||
grpc_op_error error); |
||||
/* Append a call to the end of a metadata buffer: may allocate memory */ |
||||
void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, grpc_call_op *op); |
||||
/* Flush all queued operations from the metadata buffer to the element below
|
||||
self */ |
||||
void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer, |
||||
grpc_call_element *self); |
||||
/* Count the number of queued elements in the buffer. */ |
||||
size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer); |
||||
/* Extract elements as a grpc_metadata*, for presentation to applications.
|
||||
The returned buffer must be freed with |
||||
grpc_metadata_buffer_cleanup_elements. |
||||
Clears the metadata buffer (this is a one-shot operation) */ |
||||
grpc_metadata *grpc_metadata_buffer_extract_elements( |
||||
grpc_metadata_buffer *buffer); |
||||
void grpc_metadata_buffer_cleanup_elements(void *elements, grpc_op_error error); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H */ |
@ -0,0 +1,136 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GRPC_BASIC_PROFILER |
||||
|
||||
#include "src/core/profiling/timers.h" |
||||
#include "src/core/profiling/timers_preciseclock.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd.h> |
||||
#include <stdio.h> |
||||
|
||||
typedef enum { |
||||
BEGIN = '{', |
||||
END = '}', |
||||
MARK = '.', |
||||
IMPORTANT = '!' |
||||
} marker_type; |
||||
|
||||
typedef struct grpc_timer_entry { |
||||
grpc_precise_clock tm; |
||||
int tag; |
||||
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 " GRPC_PRECISE_CLOCK_FORMAT " %p %c %d %p %s %d\n", |
||||
GRPC_PRECISE_CLOCK_PRINTF_ARGS(&entry->tm), |
||||
(void*)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tag, |
||||
entry->id, entry->file, entry->line); |
||||
} |
||||
|
||||
/* Now clear out the log */ |
||||
count = 0; |
||||
} |
||||
|
||||
static void grpc_timers_log_add(int tag, 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++]; |
||||
|
||||
grpc_precise_clock_now(&entry->tm); |
||||
entry->tag = tag; |
||||
entry->type = type; |
||||
entry->id = id; |
||||
entry->file = file; |
||||
entry->line = line; |
||||
} |
||||
|
||||
/* Latency profiler API implementation. */ |
||||
void grpc_timer_add_mark(int tag, void* id, const char* file, int line) { |
||||
if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { |
||||
grpc_timers_log_add(tag, MARK, id, file, line); |
||||
} |
||||
} |
||||
|
||||
void grpc_timer_add_important_mark(int tag, void* id, const char* file, |
||||
int line) { |
||||
if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { |
||||
grpc_timers_log_add(tag, IMPORTANT, id, file, line); |
||||
} |
||||
} |
||||
|
||||
void grpc_timer_begin(int tag, void* id, const char* file, int line) { |
||||
if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { |
||||
grpc_timers_log_add(tag, BEGIN, id, file, line); |
||||
} |
||||
} |
||||
|
||||
void grpc_timer_end(int tag, void* id, const char* file, int line) { |
||||
if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { |
||||
grpc_timers_log_add(tag, 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 */ |
@ -0,0 +1,7 @@ |
||||
provider _stap { |
||||
probe add_mark(int tag); |
||||
probe add_important_mark(int tag); |
||||
probe timing_ns_begin(int tag); |
||||
probe timing_ns_end(int tag); |
||||
}; |
||||
|
@ -0,0 +1,62 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GRPC_STAP_PROFILER |
||||
|
||||
#include "src/core/profiling/timers.h" |
||||
|
||||
#include <sys/sdt.h> |
||||
/* 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, void* id, const char* file, int line) { |
||||
_STAP_ADD_MARK(tag); |
||||
} |
||||
|
||||
void grpc_timer_add_important_mark(int tag, void* id, const char* file, |
||||
int line) { |
||||
_STAP_ADD_IMPORTANT_MARK(tag); |
||||
} |
||||
|
||||
void grpc_timer_begin(int tag, void* id, const char* file, int line) { |
||||
_STAP_TIMING_NS_BEGIN(tag); |
||||
} |
||||
|
||||
void grpc_timer_end(int tag, void* id, const char* file, int line) { |
||||
_STAP_TIMING_NS_END(tag); |
||||
} |
||||
|
||||
#endif /* GRPC_STAP_PROFILER */ |
@ -0,0 +1,141 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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, void *id, const char *file, int line); |
||||
void grpc_timer_add_important_mark(int tag, void *id, const char *file, |
||||
int line); |
||||
void grpc_timer_begin(int tag, void *id, const char *file, int line); |
||||
void grpc_timer_end(int tag, 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, ((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, ((void *)(gpr_intptr)(id)), __FILE__, \
|
||||
__LINE__); \
|
||||
} |
||||
|
||||
#define GRPC_TIMER_BEGIN(tag, id) \ |
||||
if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \
|
||||
grpc_timer_begin(tag, ((void *)(gpr_intptr)(id)), __FILE__, __LINE__); \
|
||||
} |
||||
|
||||
#define GRPC_TIMER_END(tag, id) \ |
||||
if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \
|
||||
grpc_timer_end(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 */ |
@ -0,0 +1,95 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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_PRECISECLOCK_H |
||||
#define GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H |
||||
|
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
#include <stdio.h> |
||||
|
||||
#ifdef GRPC_TIMERS_RDTSC |
||||
typedef long long int grpc_precise_clock; |
||||
#if defined(__i386__) |
||||
static void grpc_precise_clock_now(grpc_precise_clock *clk) { |
||||
grpc_precise_clock ret; |
||||
__asm__ volatile("rdtsc" : "=A"(ret)); |
||||
*clk = ret; |
||||
} |
||||
|
||||
// ----------------------------------------------------------------
|
||||
#elif defined(__x86_64__) || defined(__amd64__) |
||||
static void grpc_precise_clock_now(grpc_precise_clock *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 double cycles_per_second = 0.0; |
||||
static void grpc_precise_clock_init() { |
||||
time_t start = time(NULL); |
||||
grpc_precise_clock start_time; |
||||
grpc_precise_clock end_time; |
||||
while (time(NULL) == start) |
||||
; |
||||
grpc_precise_clock_now(&start_time); |
||||
while (time(NULL) == start + 1) |
||||
; |
||||
grpc_precise_clock_now(&end_time); |
||||
cycles_per_second = end_time - start_time; |
||||
} |
||||
static double grpc_precise_clock_scaling_factor() { |
||||
gpr_once_init(&precise_clock_init, grpc_precise_clock_init); |
||||
return 1e6 / cycles_per_second; |
||||
} |
||||
#define GRPC_PRECISE_CLOCK_FORMAT "%f" |
||||
#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \ |
||||
(*(clk)*grpc_precise_clock_scaling_factor()) |
||||
#else |
||||
typedef struct grpc_precise_clock grpc_precise_clock; |
||||
struct grpc_precise_clock { |
||||
gpr_timespec clock; |
||||
}; |
||||
static void grpc_precise_clock_now(grpc_precise_clock* clk) { |
||||
clk->clock = gpr_now(); |
||||
} |
||||
#define GRPC_PRECISE_CLOCK_FORMAT "%ld.%09d" |
||||
#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \ |
||||
(clk)->clock.tv_sec, (clk)->clock.tv_nsec |
||||
static void grpc_precise_clock_print(const grpc_precise_clock* clk, FILE* fp) { |
||||
fprintf(fp, "%ld.%09d", clk->clock.tv_sec, clk->clock.tv_nsec); |
||||
} |
||||
#endif /* GRPC_TIMERS_RDTSC */ |
||||
|
||||
#endif /* GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H */ |
@ -0,0 +1,596 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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 <string.h> |
||||
|
||||
#include "src/core/security/credentials.h" |
||||
#include "src/core/security/secure_endpoint.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 <grpc/support/alloc.h> |
||||
#include <grpc/support/host_port.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/slice_buffer.h> |
||||
#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. -- */ |
||||
|
||||
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); |
||||
} |
||||
|
||||
void grpc_security_connector_unref(grpc_security_connector *sc) { |
||||
if (sc == NULL) return; |
||||
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); |
||||
} |
||||
|
||||
grpc_security_connector *grpc_security_connector_ref( |
||||
grpc_security_connector *sc) { |
||||
if (sc == NULL) return NULL; |
||||
gpr_ref(&sc->refcount); |
||||
return sc; |
||||
} |
||||
|
||||
static void connector_pointer_arg_destroy(void *p) { |
||||
grpc_security_connector_unref(p); |
||||
} |
||||
|
||||
static void *connector_pointer_arg_copy(void *p) { |
||||
return grpc_security_connector_ref(p); |
||||
} |
||||
|
||||
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); |
||||
gpr_free(sc); |
||||
} |
||||
|
||||
static void fake_server_destroy(grpc_security_connector *sc) { 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 ? "<EMPTY>" : prop_name); |
||||
status = GRPC_SECURITY_ERROR; |
||||
goto end; |
||||
} |
||||
if (peer.properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) { |
||||
gpr_log(GPR_ERROR, "Invalid type of cert type property."); |
||||
status = GRPC_SECURITY_ERROR; |
||||
goto end; |
||||
} |
||||
if (strncmp(peer.properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE, |
||||
peer.properties[0].value.string.length)) { |
||||
gpr_log(GPR_ERROR, "Invalid value for cert type property."); |
||||
status = GRPC_SECURITY_ERROR; |
||||
goto end; |
||||
} |
||||
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)); |
||||
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)); |
||||
gpr_ref_init(&c->refcount, 1); |
||||
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); |
||||
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); |
||||
} |
||||
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; |
||||
} |
||||
|
||||
static grpc_security_status ssl_check_peer(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 (p->type != TSI_PEER_PROPERTY_TYPE_STRING) { |
||||
gpr_log(GPR_ERROR, "Invalid selected ALPN property."); |
||||
return GRPC_SECURITY_ERROR; |
||||
} |
||||
if (!grpc_chttp2_is_alpn_version_supported(p->value.string.data, |
||||
p->value.string.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; |
||||
} |
||||
|
||||
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(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) { |
||||
/* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */ |
||||
grpc_security_status status = ssl_check_peer(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] = |
||||
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; |
||||
} |
||||
|
||||
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); |
||||
} |
||||
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; |
||||
} |
||||
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, 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] = |
||||
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, ssl_cipher_suites(), |
||||
alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols, |
||||
&c->handshaker_factory); |
||||
if (result != TSI_OK) { |
||||
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", |
||||
tsi_result_to_string(result)); |
||||
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; |
||||
} |
||||
|
@ -0,0 +1,201 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (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 <grpc/grpc_security.h> |
||||
#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; |
||||
}; |
||||
|
||||
/* Increments the refcount. */ |
||||
grpc_security_connector *grpc_security_connector_ref( |
||||
grpc_security_connector *sc); |
||||
|
||||
/* Decrements the refcount and destroys the object if it reaches 0. */ |
||||
void grpc_security_connector_unref(grpc_security_connector *sc); |
||||
|
||||
/* 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; |
||||
} 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); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue