Merge branch 'master' of github.com:grpc/grpc into jtattermusch-patch-3
This commit is contained in:
commit
4bf27c5456
20
BUILD
20
BUILD
|
|
@ -145,12 +145,14 @@ cc_library(
|
|||
"src/core/tsi/transport_security.h",
|
||||
"src/core/tsi/transport_security_interface.h",
|
||||
"src/core/census/grpc_context.h",
|
||||
"src/core/channel/census_filter.h",
|
||||
"src/core/channel/channel_args.h",
|
||||
"src/core/channel/channel_stack.h",
|
||||
"src/core/channel/child_channel.h",
|
||||
"src/core/channel/client_channel.h",
|
||||
"src/core/channel/client_setup.h",
|
||||
"src/core/channel/connected_channel.h",
|
||||
"src/core/channel/context.h",
|
||||
"src/core/channel/http_client_filter.h",
|
||||
"src/core/channel/http_server_filter.h",
|
||||
"src/core/channel/noop_filter.h",
|
||||
|
|
@ -167,10 +169,10 @@ cc_library(
|
|||
"src/core/iomgr/iomgr_internal.h",
|
||||
"src/core/iomgr/iomgr_posix.h",
|
||||
"src/core/iomgr/pollset.h",
|
||||
"src/core/iomgr/pollset_kick.h",
|
||||
"src/core/iomgr/pollset_kick_posix.h",
|
||||
"src/core/iomgr/pollset_kick_windows.h",
|
||||
"src/core/iomgr/pollset_posix.h",
|
||||
"src/core/iomgr/pollset_set_posix.h",
|
||||
"src/core/iomgr/pollset_set_windows.h",
|
||||
"src/core/iomgr/pollset_windows.h",
|
||||
"src/core/iomgr/resolve_address.h",
|
||||
"src/core/iomgr/sockaddr.h",
|
||||
|
|
@ -271,10 +273,12 @@ cc_library(
|
|||
"src/core/iomgr/iomgr.c",
|
||||
"src/core/iomgr/iomgr_posix.c",
|
||||
"src/core/iomgr/iomgr_windows.c",
|
||||
"src/core/iomgr/pollset_kick.c",
|
||||
"src/core/iomgr/pollset_kick_posix.c",
|
||||
"src/core/iomgr/pollset_multipoller_with_epoll.c",
|
||||
"src/core/iomgr/pollset_multipoller_with_poll_posix.c",
|
||||
"src/core/iomgr/pollset_posix.c",
|
||||
"src/core/iomgr/pollset_set_posix.c",
|
||||
"src/core/iomgr/pollset_set_windows.c",
|
||||
"src/core/iomgr/pollset_windows.c",
|
||||
"src/core/iomgr/resolve_address_posix.c",
|
||||
"src/core/iomgr/resolve_address_windows.c",
|
||||
|
|
@ -366,12 +370,14 @@ cc_library(
|
|||
name = "grpc_unsecure",
|
||||
srcs = [
|
||||
"src/core/census/grpc_context.h",
|
||||
"src/core/channel/census_filter.h",
|
||||
"src/core/channel/channel_args.h",
|
||||
"src/core/channel/channel_stack.h",
|
||||
"src/core/channel/child_channel.h",
|
||||
"src/core/channel/client_channel.h",
|
||||
"src/core/channel/client_setup.h",
|
||||
"src/core/channel/connected_channel.h",
|
||||
"src/core/channel/context.h",
|
||||
"src/core/channel/http_client_filter.h",
|
||||
"src/core/channel/http_server_filter.h",
|
||||
"src/core/channel/noop_filter.h",
|
||||
|
|
@ -388,10 +394,10 @@ cc_library(
|
|||
"src/core/iomgr/iomgr_internal.h",
|
||||
"src/core/iomgr/iomgr_posix.h",
|
||||
"src/core/iomgr/pollset.h",
|
||||
"src/core/iomgr/pollset_kick.h",
|
||||
"src/core/iomgr/pollset_kick_posix.h",
|
||||
"src/core/iomgr/pollset_kick_windows.h",
|
||||
"src/core/iomgr/pollset_posix.h",
|
||||
"src/core/iomgr/pollset_set_posix.h",
|
||||
"src/core/iomgr/pollset_set_windows.h",
|
||||
"src/core/iomgr/pollset_windows.h",
|
||||
"src/core/iomgr/resolve_address.h",
|
||||
"src/core/iomgr/sockaddr.h",
|
||||
|
|
@ -470,10 +476,12 @@ cc_library(
|
|||
"src/core/iomgr/iomgr.c",
|
||||
"src/core/iomgr/iomgr_posix.c",
|
||||
"src/core/iomgr/iomgr_windows.c",
|
||||
"src/core/iomgr/pollset_kick.c",
|
||||
"src/core/iomgr/pollset_kick_posix.c",
|
||||
"src/core/iomgr/pollset_multipoller_with_epoll.c",
|
||||
"src/core/iomgr/pollset_multipoller_with_poll_posix.c",
|
||||
"src/core/iomgr/pollset_posix.c",
|
||||
"src/core/iomgr/pollset_set_posix.c",
|
||||
"src/core/iomgr/pollset_set_windows.c",
|
||||
"src/core/iomgr/pollset_windows.c",
|
||||
"src/core/iomgr/resolve_address_posix.c",
|
||||
"src/core/iomgr/resolve_address_windows.c",
|
||||
|
|
|
|||
31
build.json
31
build.json
|
|
@ -6,8 +6,8 @@
|
|||
"#": "The public version number of the library.",
|
||||
"version": {
|
||||
"major": 0,
|
||||
"minor": 9,
|
||||
"micro": 1,
|
||||
"minor": 10,
|
||||
"micro": 0,
|
||||
"build": 0
|
||||
}
|
||||
},
|
||||
|
|
@ -107,12 +107,14 @@
|
|||
],
|
||||
"headers": [
|
||||
"src/core/census/grpc_context.h",
|
||||
"src/core/channel/census_filter.h",
|
||||
"src/core/channel/channel_args.h",
|
||||
"src/core/channel/channel_stack.h",
|
||||
"src/core/channel/child_channel.h",
|
||||
"src/core/channel/client_channel.h",
|
||||
"src/core/channel/client_setup.h",
|
||||
"src/core/channel/connected_channel.h",
|
||||
"src/core/channel/context.h",
|
||||
"src/core/channel/http_client_filter.h",
|
||||
"src/core/channel/http_server_filter.h",
|
||||
"src/core/channel/noop_filter.h",
|
||||
|
|
@ -129,10 +131,10 @@
|
|||
"src/core/iomgr/iomgr_internal.h",
|
||||
"src/core/iomgr/iomgr_posix.h",
|
||||
"src/core/iomgr/pollset.h",
|
||||
"src/core/iomgr/pollset_kick.h",
|
||||
"src/core/iomgr/pollset_kick_posix.h",
|
||||
"src/core/iomgr/pollset_kick_windows.h",
|
||||
"src/core/iomgr/pollset_posix.h",
|
||||
"src/core/iomgr/pollset_set_posix.h",
|
||||
"src/core/iomgr/pollset_set_windows.h",
|
||||
"src/core/iomgr/pollset_windows.h",
|
||||
"src/core/iomgr/resolve_address.h",
|
||||
"src/core/iomgr/sockaddr.h",
|
||||
|
|
@ -211,10 +213,12 @@
|
|||
"src/core/iomgr/iomgr.c",
|
||||
"src/core/iomgr/iomgr_posix.c",
|
||||
"src/core/iomgr/iomgr_windows.c",
|
||||
"src/core/iomgr/pollset_kick.c",
|
||||
"src/core/iomgr/pollset_kick_posix.c",
|
||||
"src/core/iomgr/pollset_multipoller_with_epoll.c",
|
||||
"src/core/iomgr/pollset_multipoller_with_poll_posix.c",
|
||||
"src/core/iomgr/pollset_posix.c",
|
||||
"src/core/iomgr/pollset_set_posix.c",
|
||||
"src/core/iomgr/pollset_set_windows.c",
|
||||
"src/core/iomgr/pollset_windows.c",
|
||||
"src/core/iomgr/resolve_address_posix.c",
|
||||
"src/core/iomgr/resolve_address_windows.c",
|
||||
|
|
@ -1279,6 +1283,20 @@
|
|||
"gpr"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "grpc_security_connector_test",
|
||||
"build": "test",
|
||||
"language": "c",
|
||||
"src": [
|
||||
"test/core/security/security_connector_test.c"
|
||||
],
|
||||
"deps": [
|
||||
"grpc_test_util",
|
||||
"grpc",
|
||||
"gpr_test_util",
|
||||
"gpr"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "grpc_stream_op_test",
|
||||
"build": "test",
|
||||
|
|
@ -1361,6 +1379,9 @@
|
|||
"grpc",
|
||||
"gpr_test_util",
|
||||
"gpr"
|
||||
],
|
||||
"platforms": [
|
||||
"posix"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ channel, we use a state machine with four states, defined below:
|
|||
|
||||
CONNECTING: The channel is trying to establish a connection and is waiting to
|
||||
make progress on one of the steps involved in name resolution, TCP connection
|
||||
establishment or TLS handshake. This is the initial state for all channels upon
|
||||
establishment or TLS handshake. This may be used as the initial state for channels upon
|
||||
creation.
|
||||
|
||||
READY: The channel has successfully established a connection all the way
|
||||
|
|
@ -34,14 +34,26 @@ retries are done with exponential backoff, channels that fail to connect will
|
|||
start out spending very little time in this state but as the attempts fail
|
||||
repeatedly, the channel will spend increasingly large amounts of time in this
|
||||
state. For many non-fatal failures (e.g., TCP connection attempts timing out
|
||||
because the server is not yet available), the channel may be stuck in this
|
||||
state for an indefinitely large amount of time.
|
||||
because the server is not yet available), the channel may spend increasingly
|
||||
large amounts of time in this state.
|
||||
|
||||
FATAL_FAILURE: There has been a fatal failure and the channel will never
|
||||
attempt to establish a connection again. (e.g., a server presenting an invalid
|
||||
TLS certificate)
|
||||
IDLE: This is the state where the channel is not even trying to create a
|
||||
connection because of a lack of new or pending RPCs. New channels MAY be created
|
||||
in this state. Any attempt to start an RPC on the channel will push the channel
|
||||
out of this state to connecting. When there has been no RPC activity on a channel
|
||||
for a specified IDLE_TIMEOUT, i.e., no new or pending (active) RPCs for this
|
||||
period, channels that are READY or CONNECTING switch to IDLE. Additionaly,
|
||||
channels that receive a GOAWAY when there are no active or pending RPCs should
|
||||
also switch to IDLE to avoid connection overload at servers that are attempting
|
||||
to shed connections. We will use a default IDLE_TIMEOUT of 300 seconds (5 minutes).
|
||||
|
||||
Channels that enter this state never leave this state.
|
||||
SHUTDOWN: This channel has started shutting down. Any new RPCs should fail
|
||||
immediately. Pending RPCs may continue running till the application cancels them.
|
||||
Channels may enter this state either because the application explicitly requested
|
||||
a shutdown or if a non-recoverable error has happened during attempts to connect
|
||||
communicate . (As of 6/12/2015, there are no known errors (while connecting or
|
||||
communicating) that are classified as non-recoverable)
|
||||
Channels that enter this state never leave this state.
|
||||
|
||||
The following table lists the legal transitions from one state to another and
|
||||
corresponding reasons. Empty cells denote disallowed transitions.
|
||||
|
|
@ -52,14 +64,16 @@ corresponding reasons. Empty cells denote disallowed transitions.
|
|||
<th>CONNECTING</th>
|
||||
<th>READY</th>
|
||||
<th>TRANSIENT_FAILURE</th>
|
||||
<th>FATAL_FAILURE</th>
|
||||
<th>IDLE</th>
|
||||
<th>SHUTDOWN</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>CONNECTING</th>
|
||||
<td>Incremental progress during connection establishment</td>
|
||||
<td>All steps needed to establish a connection succeeded</td>
|
||||
<td>Any failure in any of the steps needed to establish connection</td>
|
||||
<td>Fatal failure encountered while attempting a connection.</td>
|
||||
<td>No RPC activity on channel for IDLE_TIMEOUT</td>
|
||||
<td>Shutdown triggered by application.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>READY</th>
|
||||
|
|
@ -67,7 +81,8 @@ corresponding reasons. Empty cells denote disallowed transitions.
|
|||
<td>Incremental successful communication on established channel.</td>
|
||||
<td>Any failure encountered while expecting successful communication on
|
||||
established channel.</td>
|
||||
<td></td>
|
||||
<td>No RPC activity on channel for IDLE_TIMEOUT <br>OR<br>upon receiving a GOAWAY while there are no pending RPCs.</td>
|
||||
<td>Shutdown triggered by application.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>TRANSIENT_FAILURE</th>
|
||||
|
|
@ -75,6 +90,15 @@ corresponding reasons. Empty cells denote disallowed transitions.
|
|||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>Shutdown triggered by application.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>IDLE</th>
|
||||
<td>Any new RPC activity on the channel</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>Shutdown triggered by application.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>FATAL_FAILURE</th>
|
||||
|
|
@ -82,6 +106,7 @@ corresponding reasons. Empty cells denote disallowed transitions.
|
|||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -117,7 +117,7 @@ class ServerAsyncResponseWriter GRPC_FINAL
|
|||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
// The response is dropped if the status is not OK.
|
||||
if (status.IsOk()) {
|
||||
if (status.ok()) {
|
||||
finish_buf_.AddSendMessage(msg);
|
||||
}
|
||||
finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
|
|
@ -125,7 +125,7 @@ class ServerAsyncResponseWriter GRPC_FINAL
|
|||
}
|
||||
|
||||
void FinishWithError(const Status& status, void* tag) {
|
||||
GPR_ASSERT(!status.IsOk());
|
||||
GPR_ASSERT(!status.ok());
|
||||
finish_buf_.Reset(tag);
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <list>
|
||||
|
||||
#include <grpc++/config.h>
|
||||
#include <grpc/compression.h>
|
||||
#include <grpc/grpc.h>
|
||||
|
||||
namespace grpc {
|
||||
|
|
@ -58,6 +59,9 @@ class ChannelArguments {
|
|||
void SetSslTargetNameOverride(const grpc::string& name);
|
||||
// TODO(yangg) add flow control options
|
||||
|
||||
// Set the compression level for the channel.
|
||||
void SetCompressionLevel(grpc_compression_level level);
|
||||
|
||||
// Generic channel argument setters. Only for advanced use cases.
|
||||
void SetInt(const grpc::string& key, int value);
|
||||
void SetString(const grpc::string& key, const grpc::string& value);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpc++/config.h>
|
||||
#include <grpc++/status.h>
|
||||
#include <grpc++/time.h>
|
||||
|
||||
struct grpc_call;
|
||||
|
|
@ -53,7 +54,6 @@ class ChannelInterface;
|
|||
class CompletionQueue;
|
||||
class Credentials;
|
||||
class RpcMethod;
|
||||
class Status;
|
||||
template <class R>
|
||||
class ClientReader;
|
||||
template <class W>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#define GRPCXX_IMPL_CLIENT_UNARY_CALL_H
|
||||
|
||||
#include <grpc++/config.h>
|
||||
#include <grpc++/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
|
|
@ -42,7 +43,6 @@ class ChannelInterface;
|
|||
class ClientContext;
|
||||
class CompletionQueue;
|
||||
class RpcMethod;
|
||||
class Status;
|
||||
|
||||
// Wrapper that performs a blocking unary call
|
||||
Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#define GRPCXX_IMPL_SERVICE_TYPE_H
|
||||
|
||||
#include <grpc++/config.h>
|
||||
#include <grpc++/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
|
|
@ -44,7 +45,6 @@ class RpcService;
|
|||
class Server;
|
||||
class ServerCompletionQueue;
|
||||
class ServerContext;
|
||||
class Status;
|
||||
|
||||
class SynchronousService {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ class Server GRPC_FINAL : public GrpcLibrary,
|
|||
|
||||
class SyncRequest;
|
||||
class AsyncRequest;
|
||||
class ShutdownRequest;
|
||||
|
||||
// ServerBuilder use only
|
||||
Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
|
||||
|
|
|
|||
|
|
@ -42,18 +42,17 @@ namespace grpc {
|
|||
class Status {
|
||||
public:
|
||||
Status() : code_(StatusCode::OK) {}
|
||||
explicit Status(StatusCode code) : code_(code) {}
|
||||
Status(StatusCode code, const grpc::string& details)
|
||||
: code_(code), details_(details) {}
|
||||
|
||||
// Pre-defined special status objects.
|
||||
static const Status& OK;
|
||||
static const Status& Cancelled;
|
||||
static const Status& CANCELLED;
|
||||
|
||||
StatusCode code() const { return code_; }
|
||||
grpc::string details() const { return details_; }
|
||||
StatusCode error_code() const { return code_; }
|
||||
grpc::string error_message() const { return details_; }
|
||||
|
||||
bool IsOk() const { return code_ == StatusCode::OK; }
|
||||
bool ok() const { return code_ == StatusCode::OK; }
|
||||
|
||||
private:
|
||||
StatusCode code_;
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncStreamingInterface,
|
|||
ctx_->sent_initial_metadata_ = true;
|
||||
}
|
||||
// The response is dropped if the status is not OK.
|
||||
if (status.IsOk()) {
|
||||
if (status.ok()) {
|
||||
finish_buf_.AddSendMessage(msg);
|
||||
}
|
||||
finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
|
||||
|
|
@ -623,7 +623,7 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncStreamingInterface,
|
|||
}
|
||||
|
||||
void FinishWithError(const Status& status, void* tag) {
|
||||
GPR_ASSERT(!status.IsOk());
|
||||
GPR_ASSERT(!status.ok());
|
||||
finish_buf_.Reset(tag);
|
||||
if (!ctx_->sent_initial_metadata_) {
|
||||
finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
|
|||
/** Destroys \a byte_buffer deallocating all its memory. */
|
||||
void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
|
||||
|
||||
|
||||
/** Reader for byte buffers. Iterates over slices in the byte buffer */
|
||||
struct grpc_byte_buffer_reader;
|
||||
typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
|
||||
|
|
@ -107,4 +106,4 @@ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* GRPC_BYTE_BUFFER_H */
|
||||
#endif /* GRPC_BYTE_BUFFER_H */
|
||||
|
|
|
|||
|
|
@ -55,4 +55,4 @@ struct grpc_byte_buffer_reader {
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* GRPC_BYTE_BUFFER_READER_H */
|
||||
#endif /* GRPC_BYTE_BUFFER_READER_H */
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@
|
|||
#ifndef GRPC_COMPRESSION_H
|
||||
#define GRPC_COMPRESSION_H
|
||||
|
||||
/** To be used in channel arguments */
|
||||
#define GRPC_COMPRESSION_LEVEL_ARG "grpc.compression_level"
|
||||
|
||||
/* The various compression algorithms supported by GRPC */
|
||||
typedef enum {
|
||||
GRPC_COMPRESS_NONE = 0,
|
||||
|
|
@ -43,7 +46,17 @@ typedef enum {
|
|||
GRPC_COMPRESS_ALGORITHMS_COUNT
|
||||
} grpc_compression_algorithm;
|
||||
|
||||
typedef enum {
|
||||
GRPC_COMPRESS_LEVEL_NONE = 0,
|
||||
GRPC_COMPRESS_LEVEL_LOW,
|
||||
GRPC_COMPRESS_LEVEL_MED,
|
||||
GRPC_COMPRESS_LEVEL_HIGH
|
||||
} grpc_compression_level;
|
||||
|
||||
const char *grpc_compression_algorithm_name(
|
||||
grpc_compression_algorithm algorithm);
|
||||
|
||||
#endif /* GRPC_COMPRESSION_H */
|
||||
grpc_compression_algorithm grpc_compression_algorithm_for_level(
|
||||
grpc_compression_level level);
|
||||
|
||||
#endif /* GRPC_COMPRESSION_H */
|
||||
|
|
|
|||
|
|
@ -99,7 +99,8 @@ typedef struct {
|
|||
These configuration options are modelled as key-value pairs as defined
|
||||
by grpc_arg; keys are strings to allow easy backwards-compatible extension
|
||||
by arbitrary parties.
|
||||
All evaluation is performed at channel creation time. */
|
||||
All evaluation is performed at channel creation time (i.e. the values in
|
||||
this structure need only live through the creation invocation). */
|
||||
typedef struct {
|
||||
size_t num_args;
|
||||
grpc_arg *args;
|
||||
|
|
@ -144,7 +145,10 @@ typedef enum grpc_call_error {
|
|||
/* the flags value was illegal for this call */
|
||||
GRPC_CALL_ERROR_INVALID_FLAGS,
|
||||
/* invalid metadata was passed to this call */
|
||||
GRPC_CALL_ERROR_INVALID_METADATA
|
||||
GRPC_CALL_ERROR_INVALID_METADATA,
|
||||
/* completion queue for notification has not been registered with the server
|
||||
*/
|
||||
GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE
|
||||
} grpc_call_error;
|
||||
|
||||
/* Write Flags: */
|
||||
|
|
@ -155,6 +159,8 @@ typedef enum grpc_call_error {
|
|||
/* Force compression to be disabled for a particular write
|
||||
(start_write/add_metadata). Illegal on invoke/accept. */
|
||||
#define GRPC_WRITE_NO_COMPRESS (0x00000002u)
|
||||
/* Mask of all valid flags. */
|
||||
#define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS)
|
||||
|
||||
/* A single metadata element */
|
||||
typedef struct grpc_metadata {
|
||||
|
|
@ -173,11 +179,11 @@ typedef struct grpc_metadata {
|
|||
/** The type of completion (for grpc_event) */
|
||||
typedef enum grpc_completion_type {
|
||||
/** Shutting down */
|
||||
GRPC_QUEUE_SHUTDOWN,
|
||||
GRPC_QUEUE_SHUTDOWN,
|
||||
/** No event before timeout */
|
||||
GRPC_QUEUE_TIMEOUT,
|
||||
GRPC_QUEUE_TIMEOUT,
|
||||
/** Operation completion */
|
||||
GRPC_OP_COMPLETE
|
||||
GRPC_OP_COMPLETE
|
||||
} grpc_completion_type;
|
||||
|
||||
/** The result of an operation.
|
||||
|
|
@ -186,7 +192,7 @@ typedef enum grpc_completion_type {
|
|||
typedef struct grpc_event {
|
||||
/** The type of the completion. */
|
||||
grpc_completion_type type;
|
||||
/** non-zero if the operation was successful, 0 upon failure.
|
||||
/** non-zero if the operation was successful, 0 upon failure.
|
||||
Only GRPC_OP_COMPLETE can succeed or fail. */
|
||||
int success;
|
||||
/** The tag passed to grpc_call_start_batch etc to start this operation.
|
||||
|
|
@ -221,7 +227,7 @@ typedef enum {
|
|||
GRPC_OP_SEND_INITIAL_METADATA = 0,
|
||||
/* Send a message: 0 or more of these operations can occur for each call */
|
||||
GRPC_OP_SEND_MESSAGE,
|
||||
/* Send a close from the server: one and only one instance MUST be sent from
|
||||
/* Send a close from the client: one and only one instance MUST be sent from
|
||||
the client,
|
||||
unless the call was cancelled - in which case this can be skipped */
|
||||
GRPC_OP_SEND_CLOSE_FROM_CLIENT,
|
||||
|
|
@ -240,7 +246,7 @@ typedef enum {
|
|||
the status will indicate some failure.
|
||||
*/
|
||||
GRPC_OP_RECV_STATUS_ON_CLIENT,
|
||||
/* Receive status on the server: one and only one must be made on the server
|
||||
/* Receive close on the server: one and only one must be made on the server
|
||||
*/
|
||||
GRPC_OP_RECV_CLOSE_ON_SERVER
|
||||
} grpc_op_type;
|
||||
|
|
@ -250,6 +256,7 @@ typedef enum {
|
|||
no arguments) */
|
||||
typedef struct grpc_op {
|
||||
grpc_op_type op;
|
||||
gpr_uint32 flags; /**< Write flags bitset for grpc_begin_messages */
|
||||
union {
|
||||
struct {
|
||||
size_t count;
|
||||
|
|
@ -268,6 +275,8 @@ typedef struct grpc_op {
|
|||
After the operation completes, call grpc_metadata_array_destroy on this
|
||||
value, or reuse it in a future op. */
|
||||
grpc_metadata_array *recv_initial_metadata;
|
||||
/* ownership of the byte buffer is moved to the caller; the caller must call
|
||||
grpc_byte_buffer_destroy on this value, or reuse it in a future op. */
|
||||
grpc_byte_buffer **recv_message;
|
||||
struct {
|
||||
/* ownership of the array is with the caller, but ownership of the
|
||||
|
|
@ -313,7 +322,7 @@ typedef struct grpc_op {
|
|||
} grpc_op;
|
||||
|
||||
/** Initialize the grpc library.
|
||||
|
||||
|
||||
It is not safe to call any other grpc functions before calling this.
|
||||
(To avoid overhead, little checking is done, and some things may work. We
|
||||
do not warrant that they will continue to do so in future revisions of this
|
||||
|
|
@ -321,7 +330,7 @@ typedef struct grpc_op {
|
|||
void grpc_init(void);
|
||||
|
||||
/** Shut down the grpc library.
|
||||
|
||||
|
||||
No memory is used by grpc after this call returns, nor are any instructions
|
||||
executing within the grpc library.
|
||||
Prior to calling, all application owned grpc objects must have been
|
||||
|
|
@ -332,7 +341,7 @@ void grpc_shutdown(void);
|
|||
grpc_completion_queue *grpc_completion_queue_create(void);
|
||||
|
||||
/** Blocks until an event is available, the completion queue is being shut down,
|
||||
or deadline is reached.
|
||||
or deadline is reached.
|
||||
|
||||
Returns a grpc_event with type GRPC_QUEUE_TIMEOUT on timeout,
|
||||
otherwise a grpc_event describing the event that occurred.
|
||||
|
|
@ -343,7 +352,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
|
|||
gpr_timespec deadline);
|
||||
|
||||
/** Blocks until an event with tag 'tag' is available, the completion queue is
|
||||
being shutdown or deadline is reached.
|
||||
being shutdown or deadline is reached.
|
||||
|
||||
Returns a grpc_event with type GRPC_QUEUE_TIMEOUT on timeout,
|
||||
otherwise a grpc_event describing the event that occurred.
|
||||
|
|
@ -366,8 +375,9 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
|
|||
drained and no threads are executing grpc_completion_queue_next */
|
||||
void grpc_completion_queue_destroy(grpc_completion_queue *cq);
|
||||
|
||||
/* Create a call given a grpc_channel, in order to call 'method'. All
|
||||
completions are sent to 'completion_queue'. */
|
||||
/* Create a call given a grpc_channel, in order to call 'method'. All
|
||||
completions are sent to 'completion_queue'. 'method' and 'host' need only
|
||||
live through the invocation of this function. */
|
||||
grpc_call *grpc_channel_create_call(grpc_channel *channel,
|
||||
grpc_completion_queue *completion_queue,
|
||||
const char *method, const char *host,
|
||||
|
|
@ -396,8 +406,9 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
|
|||
|
||||
/* Create a client channel to 'target'. Additional channel level configuration
|
||||
MAY be provided by grpc_channel_args, though the expectation is that most
|
||||
clients will want to simply pass NULL. See grpc_channel_args definition
|
||||
for more on this. */
|
||||
clients will want to simply pass NULL. See grpc_channel_args definition for
|
||||
more on this. The data in 'args' need only live through the invocation of
|
||||
this function. */
|
||||
grpc_channel *grpc_channel_create(const char *target,
|
||||
const grpc_channel_args *args);
|
||||
|
||||
|
|
@ -434,7 +445,9 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
|
|||
THREAD SAFETY: grpc_call_destroy is thread-compatible */
|
||||
void grpc_call_destroy(grpc_call *call);
|
||||
|
||||
/* Request notification of a new call */
|
||||
/* Request notification of a new call. 'cq_for_notification' must
|
||||
have been registered to the server via grpc_server_register_completion_queue.
|
||||
*/
|
||||
grpc_call_error grpc_server_request_call(
|
||||
grpc_server *server, grpc_call **call, grpc_call_details *details,
|
||||
grpc_metadata_array *request_metadata,
|
||||
|
|
@ -451,7 +464,9 @@ grpc_call_error grpc_server_request_call(
|
|||
void *grpc_server_register_method(grpc_server *server, const char *method,
|
||||
const char *host);
|
||||
|
||||
/* Request notification of a new pre-registered call */
|
||||
/* Request notification of a new pre-registered call. 'cq_for_notification' must
|
||||
have been registered to the server via grpc_server_register_completion_queue.
|
||||
*/
|
||||
grpc_call_error grpc_server_request_registered_call(
|
||||
grpc_server *server, void *registered_method, grpc_call **call,
|
||||
gpr_timespec *deadline, grpc_metadata_array *request_metadata,
|
||||
|
|
@ -461,12 +476,14 @@ grpc_call_error grpc_server_request_registered_call(
|
|||
|
||||
/* Create a server. Additional configuration for each incoming channel can
|
||||
be specified with args. If no additional configuration is needed, args can
|
||||
be NULL. See grpc_channel_args for more. */
|
||||
be NULL. See grpc_channel_args for more. The data in 'args' need only live
|
||||
through the invocation of this function. */
|
||||
grpc_server *grpc_server_create(const grpc_channel_args *args);
|
||||
|
||||
/* Register a completion queue with the server. Must be done for any completion
|
||||
queue that is passed to grpc_server_request_* call. Must be performed prior
|
||||
to grpc_server_start. */
|
||||
/* Register a completion queue with the server. Must be done for any
|
||||
notification completion queue that is passed to grpc_server_request_*_call
|
||||
and to grpc_server_shutdown_and_notify. Must be performed prior to
|
||||
grpc_server_start. */
|
||||
void grpc_server_register_completion_queue(grpc_server *server,
|
||||
grpc_completion_queue *cq);
|
||||
|
||||
|
|
@ -481,27 +498,30 @@ void grpc_server_start(grpc_server *server);
|
|||
/* Begin shutting down a server.
|
||||
After completion, no new calls or connections will be admitted.
|
||||
Existing calls will be allowed to complete.
|
||||
Shutdown is idempotent. */
|
||||
void grpc_server_shutdown(grpc_server *server);
|
||||
|
||||
/* As per grpc_server_shutdown, but send a GRPC_OP_COMPLETE event when
|
||||
there are no more calls being serviced.
|
||||
Send a GRPC_OP_COMPLETE event when there are no more calls being serviced.
|
||||
Shutdown is idempotent, and all tags will be notified at once if multiple
|
||||
grpc_server_shutdown_and_notify calls are made. */
|
||||
void grpc_server_shutdown_and_notify(grpc_server *server, void *tag);
|
||||
grpc_server_shutdown_and_notify calls are made. 'cq' must have been
|
||||
registered to this server via grpc_server_register_completion_queue. */
|
||||
void grpc_server_shutdown_and_notify(grpc_server *server,
|
||||
grpc_completion_queue *cq, void *tag);
|
||||
|
||||
/* Cancel all in-progress calls.
|
||||
Only usable after shutdown. */
|
||||
void grpc_server_cancel_all_calls(grpc_server *server);
|
||||
|
||||
/* Destroy a server.
|
||||
Forcefully cancels all existing calls.
|
||||
Implies grpc_server_shutdown() if one was not previously performed. */
|
||||
Shutdown must have completed beforehand (i.e. all tags generated by
|
||||
grpc_server_shutdown_and_notify must have been received, and at least
|
||||
one call to grpc_server_shutdown_and_notify must have been made). */
|
||||
void grpc_server_destroy(grpc_server *server);
|
||||
|
||||
/** Enable or disable a tracer.
|
||||
|
||||
Tracers (usually controlled by the environment variable GRPC_TRACE)
|
||||
allow printf-style debugging on GRPC internals, and are useful for
|
||||
tracking down problems in the field.
|
||||
tracking down problems in the field.
|
||||
|
||||
Use of this function is not strictly thread-safe, but the
|
||||
Use of this function is not strictly thread-safe, but the
|
||||
thread-safety issues raised by it should not be of concern. */
|
||||
int grpc_tracer_set_enabled(const char *name, int enabled);
|
||||
|
||||
|
|
|
|||
|
|
@ -195,8 +195,7 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
|
|||
|
||||
/* TODO(jboeuf): Define some well-known property names. */
|
||||
|
||||
#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME \
|
||||
"transport_security_type"
|
||||
#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type"
|
||||
#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
|
||||
#define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
|
||||
|
||||
|
|
@ -251,4 +250,4 @@ const grpc_auth_context *grpc_call_auth_context(grpc_call *call);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* GRPC_GRPC_SECURITY_H */
|
||||
#endif /* GRPC_GRPC_SECURITY_H */
|
||||
|
|
|
|||
|
|
@ -110,8 +110,9 @@ gpr_slice gpr_slice_ref(gpr_slice s);
|
|||
/* Decrement the ref count of s. If the ref count of s reaches zero, all
|
||||
slices sharing the ref count are destroyed, and considered no longer
|
||||
initialized. If s is ultimately derived from a call to gpr_slice_new(start,
|
||||
len, dest) where dest!=NULL , then (*dest)(start, len) is called. Requires
|
||||
s initialized. */
|
||||
len, dest) where dest!=NULL , then (*dest)(start) is called, else if s is
|
||||
ultimately derived from a call to gpr_slice_new_with_len(start, len, dest)
|
||||
where dest!=NULL , then (*dest)(start, len). Requires s initialized. */
|
||||
void gpr_slice_unref(gpr_slice s);
|
||||
|
||||
/* Create a slice pointing at some data. Calls malloc to allocate a refcount
|
||||
|
|
@ -175,4 +176,4 @@ int gpr_slice_str_cmp(gpr_slice a, const char *b);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* GRPC_SUPPORT_SLICE_H */
|
||||
#endif /* GRPC_SUPPORT_SLICE_H */
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#ifndef GRPC_SUPPORT_TLS_PTHREAD_H
|
||||
#define GRPC_SUPPORT_TLS_PTHREAD_H
|
||||
|
||||
#include <grpc/support/log.h> /* for GPR_ASSERT */
|
||||
#include <grpc/support/log.h> /* for GPR_ASSERT */
|
||||
#include <pthread.h>
|
||||
|
||||
/* Thread local storage based on pthread library calls.
|
||||
|
|
@ -44,8 +44,7 @@ struct gpr_pthread_thread_local {
|
|||
pthread_key_t key;
|
||||
};
|
||||
|
||||
#define GPR_TLS_DECL(name) \
|
||||
static struct gpr_pthread_thread_local name = {0}
|
||||
#define GPR_TLS_DECL(name) static struct gpr_pthread_thread_local name = {0}
|
||||
|
||||
#define gpr_tls_init(tls) GPR_ASSERT(0 == pthread_key_create(&(tls)->key, NULL))
|
||||
#define gpr_tls_destroy(tls) pthread_key_delete((tls)->key)
|
||||
|
|
|
|||
|
|
@ -854,7 +854,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
|
|||
printer->Print(" (void) response;\n");
|
||||
printer->Print(
|
||||
" return ::grpc::Status("
|
||||
"::grpc::StatusCode::UNIMPLEMENTED);\n");
|
||||
"::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
|
||||
printer->Print("}\n\n");
|
||||
} else if (ClientOnlyStreaming(method)) {
|
||||
printer->Print(*vars,
|
||||
|
|
@ -867,7 +867,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
|
|||
printer->Print(" (void) response;\n");
|
||||
printer->Print(
|
||||
" return ::grpc::Status("
|
||||
"::grpc::StatusCode::UNIMPLEMENTED);\n");
|
||||
"::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
|
||||
printer->Print("}\n\n");
|
||||
} else if (ServerOnlyStreaming(method)) {
|
||||
printer->Print(*vars,
|
||||
|
|
@ -880,7 +880,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
|
|||
printer->Print(" (void) writer;\n");
|
||||
printer->Print(
|
||||
" return ::grpc::Status("
|
||||
"::grpc::StatusCode::UNIMPLEMENTED);\n");
|
||||
"::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
|
||||
printer->Print("}\n\n");
|
||||
} else if (BidiStreaming(method)) {
|
||||
printer->Print(*vars,
|
||||
|
|
@ -892,7 +892,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
|
|||
printer->Print(" (void) stream;\n");
|
||||
printer->Print(
|
||||
" return ::grpc::Status("
|
||||
"::grpc::StatusCode::UNIMPLEMENTED);\n");
|
||||
"::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
|
||||
printer->Print("}\n\n");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,3 +115,27 @@ int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
grpc_compression_level grpc_channel_args_get_compression_level(
|
||||
const grpc_channel_args *a) {
|
||||
size_t i;
|
||||
if (a) {
|
||||
for (i = 0; a && i < a->num_args; ++i) {
|
||||
if (a->args[i].type == GRPC_ARG_INTEGER &&
|
||||
!strcmp(GRPC_COMPRESSION_LEVEL_ARG, a->args[i].key)) {
|
||||
return a->args[i].value.integer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GRPC_COMPRESS_LEVEL_NONE;
|
||||
}
|
||||
|
||||
void grpc_channel_args_set_compression_level(
|
||||
grpc_channel_args **a, grpc_compression_level level) {
|
||||
grpc_arg tmp;
|
||||
tmp.type = GRPC_ARG_INTEGER;
|
||||
tmp.key = GRPC_COMPRESSION_LEVEL_ARG;
|
||||
tmp.value.integer = level;
|
||||
*a = grpc_channel_args_copy_and_add(*a, &tmp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,21 +34,31 @@
|
|||
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H
|
||||
#define GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H
|
||||
|
||||
#include <grpc/compression.h>
|
||||
#include <grpc/grpc.h>
|
||||
|
||||
/* Copy some arguments */
|
||||
grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
|
||||
|
||||
/* Copy some arguments and add the to_add parameter in the end.
|
||||
/** Copy some arguments and add the to_add parameter in the end.
|
||||
If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */
|
||||
grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
|
||||
const grpc_arg *to_add);
|
||||
|
||||
/* Destroy arguments created by grpc_channel_args_copy */
|
||||
/** Destroy arguments created by grpc_channel_args_copy */
|
||||
void grpc_channel_args_destroy(grpc_channel_args *a);
|
||||
|
||||
/* Reads census_enabled settings from channel args. Returns 1 if census_enabled
|
||||
is specified in channel args, otherwise returns 0. */
|
||||
/** Reads census_enabled settings from channel args. Returns 1 if census_enabled
|
||||
* is specified in channel args, otherwise returns 0. */
|
||||
int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
|
||||
|
||||
/** Returns the compression level set in \a a. */
|
||||
grpc_compression_level grpc_channel_args_get_compression_level(
|
||||
const grpc_channel_args *a);
|
||||
|
||||
/** Sets the compression level in \a a to \a level. Setting it to
|
||||
* GRPC_COMPRESS_LEVEL_NONE disables compression for the channel. */
|
||||
void grpc_channel_args_set_compression_level(
|
||||
grpc_channel_args **a, grpc_compression_level level);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */
|
||||
|
|
|
|||
|
|
@ -211,9 +211,3 @@ void grpc_call_element_send_cancel(grpc_call_element *cur_elem) {
|
|||
op.cancel_with_status = GRPC_STATUS_CANCELLED;
|
||||
grpc_call_next_op(cur_elem, &op);
|
||||
}
|
||||
|
||||
void grpc_call_element_recv_status(grpc_call_element *cur_elem,
|
||||
grpc_status_code status,
|
||||
const char *message) {
|
||||
abort();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,9 +157,10 @@ static void lb_destroy_channel_elem(grpc_channel_element *elem) {
|
|||
}
|
||||
|
||||
const grpc_channel_filter grpc_child_channel_top_filter = {
|
||||
lb_start_transport_op, lb_channel_op, sizeof(lb_call_data),
|
||||
lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data),
|
||||
lb_init_channel_elem, lb_destroy_channel_elem, "child-channel",
|
||||
lb_start_transport_op, lb_channel_op,
|
||||
sizeof(lb_call_data), lb_init_call_elem, lb_destroy_call_elem,
|
||||
sizeof(lb_channel_data), lb_init_channel_elem, lb_destroy_channel_elem,
|
||||
"child-channel",
|
||||
};
|
||||
|
||||
/* grpc_child_channel proper */
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "src/core/channel/child_channel.h"
|
||||
#include "src/core/channel/connected_channel.h"
|
||||
#include "src/core/iomgr/iomgr.h"
|
||||
#include "src/core/iomgr/pollset_set.h"
|
||||
#include "src/core/support/string.h"
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
|
|
@ -101,10 +102,17 @@ struct call_data {
|
|||
static int prepare_activate(grpc_call_element *elem,
|
||||
grpc_child_channel *on_child) {
|
||||
call_data *calld = elem->call_data;
|
||||
channel_data *chand = elem->channel_data;
|
||||
if (calld->state == CALL_CANCELLED) return 0;
|
||||
|
||||
/* no more access to calld->s.waiting allowed */
|
||||
GPR_ASSERT(calld->state == CALL_WAITING);
|
||||
|
||||
if (calld->s.waiting_op.bind_pollset) {
|
||||
grpc_transport_setup_del_interested_party(chand->transport_setup,
|
||||
calld->s.waiting_op.bind_pollset);
|
||||
}
|
||||
|
||||
calld->state = CALL_ACTIVE;
|
||||
|
||||
/* create a child call */
|
||||
|
|
@ -131,7 +139,11 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) {
|
|||
size_t new_count;
|
||||
size_t i;
|
||||
for (i = 0, new_count = 0; i < chand->waiting_child_count; i++) {
|
||||
if (chand->waiting_children[i] == calld) continue;
|
||||
if (chand->waiting_children[i] == calld) {
|
||||
grpc_transport_setup_del_interested_party(
|
||||
chand->transport_setup, calld->s.waiting_op.bind_pollset);
|
||||
continue;
|
||||
}
|
||||
chand->waiting_children[new_count++] = chand->waiting_children[i];
|
||||
}
|
||||
GPR_ASSERT(new_count == chand->waiting_child_count - 1 ||
|
||||
|
|
@ -166,6 +178,9 @@ static void handle_op_after_cancellation(grpc_call_element *elem,
|
|||
*op->recv_state = GRPC_STREAM_CLOSED;
|
||||
op->on_done_recv(op->recv_user_data, 1);
|
||||
}
|
||||
if (op->on_consumed) {
|
||||
op->on_consumed(op->on_consumed_user_data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void cc_start_transport_op(grpc_call_element *elem,
|
||||
|
|
@ -191,6 +206,7 @@ static void cc_start_transport_op(grpc_call_element *elem,
|
|||
handle_op_after_cancellation(elem, op);
|
||||
} else {
|
||||
calld->state = CALL_WAITING;
|
||||
calld->s.waiting_op.bind_pollset = NULL;
|
||||
if (chand->active_child) {
|
||||
/* channel is connected - use the connected stack */
|
||||
if (prepare_activate(elem, chand->active_child)) {
|
||||
|
|
@ -222,6 +238,8 @@ static void cc_start_transport_op(grpc_call_element *elem,
|
|||
}
|
||||
calld->s.waiting_op = *op;
|
||||
chand->waiting_children[chand->waiting_child_count++] = calld;
|
||||
grpc_transport_setup_add_interested_party(chand->transport_setup,
|
||||
op->bind_pollset);
|
||||
gpr_mu_unlock(&chand->mu);
|
||||
|
||||
/* finally initiate transport setup if needed */
|
||||
|
|
@ -257,6 +275,9 @@ static void cc_start_transport_op(grpc_call_element *elem,
|
|||
calld->s.waiting_op.recv_user_data = op->recv_user_data;
|
||||
}
|
||||
gpr_mu_unlock(&chand->mu);
|
||||
if (op->on_consumed) {
|
||||
op->on_consumed(op->on_consumed_user_data, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CALL_CANCELLED:
|
||||
|
|
@ -365,12 +386,24 @@ static void init_call_elem(grpc_call_element *elem,
|
|||
/* Destructor for call_data */
|
||||
static void destroy_call_elem(grpc_call_element *elem) {
|
||||
call_data *calld = elem->call_data;
|
||||
channel_data *chand = elem->channel_data;
|
||||
|
||||
/* if the call got activated, we need to destroy the child stack also, and
|
||||
remove it from the in-flight requests tracked by the child_entry we
|
||||
picked */
|
||||
if (calld->state == CALL_ACTIVE) {
|
||||
grpc_child_call_destroy(calld->s.active.child_call);
|
||||
gpr_mu_lock(&chand->mu);
|
||||
switch (calld->state) {
|
||||
case CALL_ACTIVE:
|
||||
gpr_mu_unlock(&chand->mu);
|
||||
grpc_child_call_destroy(calld->s.active.child_call);
|
||||
break;
|
||||
case CALL_WAITING:
|
||||
remove_waiting_child(chand, calld);
|
||||
gpr_mu_unlock(&chand->mu);
|
||||
break;
|
||||
default:
|
||||
gpr_mu_unlock(&chand->mu);
|
||||
break;
|
||||
}
|
||||
GPR_ASSERT(calld->state != CALL_WAITING);
|
||||
}
|
||||
|
|
@ -416,9 +449,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
|
|||
}
|
||||
|
||||
const grpc_channel_filter grpc_client_channel_filter = {
|
||||
cc_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
|
||||
destroy_call_elem, sizeof(channel_data), init_channel_elem,
|
||||
destroy_channel_elem, "client-channel",
|
||||
cc_start_transport_op, channel_op, sizeof(call_data),
|
||||
init_call_elem, destroy_call_elem, sizeof(channel_data),
|
||||
init_channel_elem, destroy_channel_elem, "client-channel",
|
||||
};
|
||||
|
||||
grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ struct grpc_client_setup {
|
|||
gpr_cv cv;
|
||||
grpc_client_setup_request *active_request;
|
||||
int refs;
|
||||
/** The set of pollsets that are currently interested in this
|
||||
connection being established */
|
||||
grpc_pollset_set interested_parties;
|
||||
};
|
||||
|
||||
struct grpc_client_setup_request {
|
||||
|
|
@ -68,14 +71,22 @@ gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) {
|
|||
return r->deadline;
|
||||
}
|
||||
|
||||
grpc_pollset_set *grpc_client_setup_get_interested_parties(
|
||||
grpc_client_setup_request *r) {
|
||||
return &r->setup->interested_parties;
|
||||
}
|
||||
|
||||
static void destroy_setup(grpc_client_setup *s) {
|
||||
gpr_mu_destroy(&s->mu);
|
||||
gpr_cv_destroy(&s->cv);
|
||||
s->done(s->user_data);
|
||||
grpc_channel_args_destroy(s->args);
|
||||
grpc_pollset_set_destroy(&s->interested_parties);
|
||||
gpr_free(s);
|
||||
}
|
||||
|
||||
static void destroy_request(grpc_client_setup_request *r) { gpr_free(r); }
|
||||
|
||||
/* initiate handshaking */
|
||||
static void setup_initiate(grpc_transport_setup *sp) {
|
||||
grpc_client_setup *s = (grpc_client_setup *)sp;
|
||||
|
|
@ -83,8 +94,7 @@ static void setup_initiate(grpc_transport_setup *sp) {
|
|||
int in_alarm = 0;
|
||||
|
||||
r->setup = s;
|
||||
/* TODO(klempner): Actually set a deadline */
|
||||
r->deadline = gpr_inf_future;
|
||||
r->deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(60));
|
||||
|
||||
gpr_mu_lock(&s->mu);
|
||||
GPR_ASSERT(s->refs > 0);
|
||||
|
|
@ -104,10 +114,30 @@ static void setup_initiate(grpc_transport_setup *sp) {
|
|||
if (!in_alarm) {
|
||||
s->initiate(s->user_data, r);
|
||||
} else {
|
||||
gpr_free(r);
|
||||
destroy_request(r);
|
||||
}
|
||||
}
|
||||
|
||||
/** implementation of add_interested_party for setup vtable */
|
||||
static void setup_add_interested_party(grpc_transport_setup *sp,
|
||||
grpc_pollset *pollset) {
|
||||
grpc_client_setup *s = (grpc_client_setup *)sp;
|
||||
|
||||
gpr_mu_lock(&s->mu);
|
||||
grpc_pollset_set_add_pollset(&s->interested_parties, pollset);
|
||||
gpr_mu_unlock(&s->mu);
|
||||
}
|
||||
|
||||
/** implementation of del_interested_party for setup vtable */
|
||||
static void setup_del_interested_party(grpc_transport_setup *sp,
|
||||
grpc_pollset *pollset) {
|
||||
grpc_client_setup *s = (grpc_client_setup *)sp;
|
||||
|
||||
gpr_mu_lock(&s->mu);
|
||||
grpc_pollset_set_del_pollset(&s->interested_parties, pollset);
|
||||
gpr_mu_unlock(&s->mu);
|
||||
}
|
||||
|
||||
/* cancel handshaking: cancel all requests, and shutdown (the caller promises
|
||||
not to initiate again) */
|
||||
static void setup_cancel(grpc_transport_setup *sp) {
|
||||
|
|
@ -137,7 +167,8 @@ static void setup_cancel(grpc_transport_setup *sp) {
|
|||
}
|
||||
}
|
||||
|
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r) {
|
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r,
|
||||
const char *reason) {
|
||||
gpr_mu_lock(&r->setup->mu);
|
||||
if (r->setup->cancelled) {
|
||||
gpr_mu_unlock(&r->setup->mu);
|
||||
|
|
@ -148,7 +179,8 @@ int grpc_client_setup_cb_begin(grpc_client_setup_request *r) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r) {
|
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r,
|
||||
const char *reason) {
|
||||
gpr_mu_lock(&r->setup->mu);
|
||||
r->setup->in_cb--;
|
||||
if (r->setup->cancelled) gpr_cv_signal(&r->setup->cv);
|
||||
|
|
@ -156,8 +188,9 @@ void grpc_client_setup_cb_end(grpc_client_setup_request *r) {
|
|||
}
|
||||
|
||||
/* vtable for transport setup */
|
||||
static const grpc_transport_setup_vtable setup_vtable = {setup_initiate,
|
||||
setup_cancel};
|
||||
static const grpc_transport_setup_vtable setup_vtable = {
|
||||
setup_initiate, setup_add_interested_party, setup_del_interested_party,
|
||||
setup_cancel};
|
||||
|
||||
void grpc_client_setup_create_and_attach(
|
||||
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
|
||||
|
|
@ -180,42 +213,44 @@ void grpc_client_setup_create_and_attach(
|
|||
s->in_alarm = 0;
|
||||
s->in_cb = 0;
|
||||
s->cancelled = 0;
|
||||
grpc_pollset_set_init(&s->interested_parties);
|
||||
|
||||
grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base);
|
||||
}
|
||||
|
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r) {
|
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r,
|
||||
const char *reason) {
|
||||
int result;
|
||||
if (gpr_time_cmp(gpr_now(), r->deadline) > 0) {
|
||||
return 0;
|
||||
result = 0;
|
||||
} else {
|
||||
gpr_mu_lock(&r->setup->mu);
|
||||
result = r->setup->active_request == r;
|
||||
gpr_mu_unlock(&r->setup->mu);
|
||||
}
|
||||
gpr_mu_lock(&r->setup->mu);
|
||||
result = r->setup->active_request == r;
|
||||
gpr_mu_unlock(&r->setup->mu);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void backoff_alarm_done(void *arg /* grpc_client_setup */, int success) {
|
||||
grpc_client_setup *s = arg;
|
||||
grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
|
||||
r->setup = s;
|
||||
/* TODO(klempner): Set this to something useful */
|
||||
r->deadline = gpr_inf_future;
|
||||
static void backoff_alarm_done(void *arg /* grpc_client_setup_request */,
|
||||
int success) {
|
||||
grpc_client_setup_request *r = arg;
|
||||
grpc_client_setup *s = r->setup;
|
||||
/* Handle status cancelled? */
|
||||
gpr_mu_lock(&s->mu);
|
||||
s->active_request = r;
|
||||
s->in_alarm = 0;
|
||||
if (!success) {
|
||||
if (s->active_request != NULL || !success) {
|
||||
if (0 == --s->refs) {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
destroy_setup(s);
|
||||
gpr_free(r);
|
||||
destroy_request(r);
|
||||
return;
|
||||
} else {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
destroy_request(r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
s->active_request = r;
|
||||
gpr_mu_unlock(&s->mu);
|
||||
s->initiate(s->user_data, r);
|
||||
}
|
||||
|
|
@ -231,16 +266,12 @@ void grpc_client_setup_request_finish(grpc_client_setup_request *r,
|
|||
} else {
|
||||
retry = 0;
|
||||
}
|
||||
|
||||
if (!retry && 0 == --s->refs) {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
destroy_setup(s);
|
||||
gpr_free(r);
|
||||
return;
|
||||
}
|
||||
|
||||
gpr_free(r);
|
||||
|
||||
if (retry) {
|
||||
destroy_request(r);
|
||||
} else if (retry) {
|
||||
/* TODO(klempner): Replace these values with further consideration. 2x is
|
||||
probably too aggressive of a backoff. */
|
||||
gpr_timespec max_backoff = gpr_time_from_minutes(2);
|
||||
|
|
@ -248,15 +279,17 @@ void grpc_client_setup_request_finish(grpc_client_setup_request *r,
|
|||
gpr_timespec deadline = gpr_time_add(s->current_backoff_interval, now);
|
||||
GPR_ASSERT(!s->in_alarm);
|
||||
s->in_alarm = 1;
|
||||
grpc_alarm_init(&s->backoff_alarm, deadline, backoff_alarm_done, s, now);
|
||||
grpc_alarm_init(&s->backoff_alarm, deadline, backoff_alarm_done, r, now);
|
||||
s->current_backoff_interval =
|
||||
gpr_time_add(s->current_backoff_interval, s->current_backoff_interval);
|
||||
if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) {
|
||||
s->current_backoff_interval = max_backoff;
|
||||
}
|
||||
gpr_mu_unlock(&s->mu);
|
||||
} else {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
destroy_request(r);
|
||||
}
|
||||
|
||||
gpr_mu_unlock(&s->mu);
|
||||
}
|
||||
|
||||
const grpc_channel_args *grpc_client_setup_get_channel_args(
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ void grpc_client_setup_create_and_attach(
|
|||
/* Check that r is the active request: needs to be performed at each callback.
|
||||
If this races, we'll have two connection attempts running at once and the
|
||||
old one will get cleaned up in due course, which is fine. */
|
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r);
|
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r,
|
||||
const char *reason);
|
||||
void grpc_client_setup_request_finish(grpc_client_setup_request *r,
|
||||
int was_successful);
|
||||
const grpc_channel_args *grpc_client_setup_get_channel_args(
|
||||
|
|
@ -61,13 +62,16 @@ const grpc_channel_args *grpc_client_setup_get_channel_args(
|
|||
/* Call before calling back into the setup listener, and call only if
|
||||
this function returns 1. If it returns 1, also promise to call
|
||||
grpc_client_setup_cb_end */
|
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r);
|
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r);
|
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r,
|
||||
const char *reason);
|
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r, const char *reason);
|
||||
|
||||
/* Get the deadline for a request passed in to initiate. Implementations should
|
||||
make a best effort to honor this deadline. */
|
||||
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r);
|
||||
grpc_pollset_set *grpc_client_setup_get_interested_parties(
|
||||
grpc_client_setup_request *r);
|
||||
|
||||
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <grpc/compression.h>
|
||||
|
||||
const char *grpc_compression_algorithm_name(
|
||||
|
|
@ -47,3 +48,20 @@ const char *grpc_compression_algorithm_name(
|
|||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
/* TODO(dgq): Add the ability to specify parameters to the individual
|
||||
* compression algorithms */
|
||||
grpc_compression_algorithm grpc_compression_algorithm_for_level(
|
||||
grpc_compression_level level) {
|
||||
switch (level) {
|
||||
case GRPC_COMPRESS_LEVEL_NONE:
|
||||
return GRPC_COMPRESS_NONE;
|
||||
case GRPC_COMPRESS_LEVEL_LOW:
|
||||
case GRPC_COMPRESS_LEVEL_MED:
|
||||
case GRPC_COMPRESS_LEVEL_HIGH:
|
||||
return GRPC_COMPRESS_DEFLATE;
|
||||
default:
|
||||
/* we shouldn't be making it here */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,4 +49,4 @@ int grpc_msg_compress(grpc_compression_algorithm algorithm,
|
|||
int grpc_msg_decompress(grpc_compression_algorithm algorithm,
|
||||
gpr_slice_buffer *input, gpr_slice_buffer *output);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H */
|
||||
|
|
|
|||
|
|
@ -60,14 +60,26 @@ typedef struct {
|
|||
int use_ssl;
|
||||
grpc_httpcli_response_cb on_response;
|
||||
void *user_data;
|
||||
grpc_httpcli_context *context;
|
||||
grpc_pollset *pollset;
|
||||
grpc_iomgr_object iomgr_obj;
|
||||
} internal_request;
|
||||
|
||||
static grpc_httpcli_get_override g_get_override = NULL;
|
||||
static grpc_httpcli_post_override g_post_override = NULL;
|
||||
|
||||
void grpc_httpcli_context_init(grpc_httpcli_context *context) {
|
||||
grpc_pollset_set_init(&context->pollset_set);
|
||||
}
|
||||
|
||||
void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
|
||||
grpc_pollset_set_destroy(&context->pollset_set);
|
||||
}
|
||||
|
||||
static void next_address(internal_request *req);
|
||||
|
||||
static void finish(internal_request *req, int success) {
|
||||
grpc_pollset_set_del_pollset(&req->context->pollset_set, req->pollset);
|
||||
req->on_response(req->user_data, success ? &req->parser.r : NULL);
|
||||
grpc_httpcli_parser_destroy(&req->parser);
|
||||
if (req->addresses != NULL) {
|
||||
|
|
@ -78,6 +90,7 @@ static void finish(internal_request *req, int success) {
|
|||
}
|
||||
gpr_slice_unref(req->request_text);
|
||||
gpr_free(req->host);
|
||||
grpc_iomgr_unregister_object(&req->iomgr_obj);
|
||||
gpr_free(req);
|
||||
}
|
||||
|
||||
|
|
@ -198,8 +211,9 @@ static void next_address(internal_request *req) {
|
|||
return;
|
||||
}
|
||||
addr = &req->addresses->addrs[req->next_address++];
|
||||
grpc_tcp_client_connect(on_connected, req, (struct sockaddr *)&addr->addr,
|
||||
addr->len, req->deadline);
|
||||
grpc_tcp_client_connect(on_connected, req, &req->context->pollset_set,
|
||||
(struct sockaddr *)&addr->addr, addr->len,
|
||||
req->deadline);
|
||||
}
|
||||
|
||||
static void on_resolved(void *arg, grpc_resolved_addresses *addresses) {
|
||||
|
|
@ -213,10 +227,12 @@ static void on_resolved(void *arg, grpc_resolved_addresses *addresses) {
|
|||
next_address(req);
|
||||
}
|
||||
|
||||
void grpc_httpcli_get(const grpc_httpcli_request *request,
|
||||
void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset,
|
||||
const grpc_httpcli_request *request,
|
||||
gpr_timespec deadline,
|
||||
grpc_httpcli_response_cb on_response, void *user_data) {
|
||||
internal_request *req;
|
||||
char *name;
|
||||
if (g_get_override &&
|
||||
g_get_override(request, deadline, on_response, user_data)) {
|
||||
return;
|
||||
|
|
@ -229,19 +245,27 @@ void grpc_httpcli_get(const grpc_httpcli_request *request,
|
|||
req->user_data = user_data;
|
||||
req->deadline = deadline;
|
||||
req->use_ssl = request->use_ssl;
|
||||
req->context = context;
|
||||
req->pollset = pollset;
|
||||
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
|
||||
grpc_iomgr_register_object(&req->iomgr_obj, name);
|
||||
gpr_free(name);
|
||||
if (req->use_ssl) {
|
||||
req->host = gpr_strdup(request->host);
|
||||
}
|
||||
|
||||
grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset);
|
||||
grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
|
||||
on_resolved, req);
|
||||
}
|
||||
|
||||
void grpc_httpcli_post(const grpc_httpcli_request *request,
|
||||
void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
|
||||
const grpc_httpcli_request *request,
|
||||
const char *body_bytes, size_t body_size,
|
||||
gpr_timespec deadline,
|
||||
grpc_httpcli_response_cb on_response, void *user_data) {
|
||||
internal_request *req;
|
||||
char *name;
|
||||
if (g_post_override && g_post_override(request, body_bytes, body_size,
|
||||
deadline, on_response, user_data)) {
|
||||
return;
|
||||
|
|
@ -255,10 +279,16 @@ void grpc_httpcli_post(const grpc_httpcli_request *request,
|
|||
req->user_data = user_data;
|
||||
req->deadline = deadline;
|
||||
req->use_ssl = request->use_ssl;
|
||||
req->context = context;
|
||||
req->pollset = pollset;
|
||||
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
|
||||
grpc_iomgr_register_object(&req->iomgr_obj, name);
|
||||
gpr_free(name);
|
||||
if (req->use_ssl) {
|
||||
req->host = gpr_strdup(request->host);
|
||||
}
|
||||
|
||||
grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset);
|
||||
grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
|
||||
on_resolved, req);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
|
||||
#include <grpc/support/time.h>
|
||||
|
||||
#include "src/core/iomgr/pollset_set.h"
|
||||
|
||||
/* User agent this library reports */
|
||||
#define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0"
|
||||
/* Maximum length of a header string of the form 'Key: Value\r\n' */
|
||||
|
|
@ -49,6 +51,13 @@ typedef struct grpc_httpcli_header {
|
|||
char *value;
|
||||
} grpc_httpcli_header;
|
||||
|
||||
/* Tracks in-progress http requests
|
||||
TODO(ctiller): allow caching and capturing multiple requests for the
|
||||
same content and combining them */
|
||||
typedef struct grpc_httpcli_context {
|
||||
grpc_pollset_set pollset_set;
|
||||
} grpc_httpcli_context;
|
||||
|
||||
/* A request */
|
||||
typedef struct grpc_httpcli_request {
|
||||
/* The host name to connect to */
|
||||
|
|
@ -80,7 +89,14 @@ typedef struct grpc_httpcli_response {
|
|||
typedef void (*grpc_httpcli_response_cb)(void *user_data,
|
||||
const grpc_httpcli_response *response);
|
||||
|
||||
void grpc_httpcli_context_init(grpc_httpcli_context *context);
|
||||
void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
|
||||
|
||||
/* Asynchronously perform a HTTP GET.
|
||||
'context' specifies the http context under which to do the get
|
||||
'pollset' indicates a grpc_pollset that is interested in the result
|
||||
of the get - work on this pollset may be used to progress the get
|
||||
operation
|
||||
'request' contains request parameters - these are caller owned and can be
|
||||
destroyed once the call returns
|
||||
'deadline' contains a deadline for the request (or gpr_inf_future)
|
||||
|
|
@ -88,14 +104,28 @@ typedef void (*grpc_httpcli_response_cb)(void *user_data,
|
|||
lifetime of the request
|
||||
'on_response' is a callback to report results to (and 'user_data' is a user
|
||||
supplied pointer to pass to said call) */
|
||||
void grpc_httpcli_get(const grpc_httpcli_request *request,
|
||||
void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset,
|
||||
const grpc_httpcli_request *request,
|
||||
gpr_timespec deadline,
|
||||
grpc_httpcli_response_cb on_response, void *user_data);
|
||||
|
||||
/* Asynchronously perform a HTTP POST.
|
||||
When there is no body, pass in NULL as body_bytes.
|
||||
'context' specifies the http context under which to do the post
|
||||
'pollset' indicates a grpc_pollset that is interested in the result
|
||||
of the post - work on this pollset may be used to progress the post
|
||||
operation
|
||||
'request' contains request parameters - these are caller owned and can be
|
||||
destroyed once the call returns
|
||||
'body_bytes' and 'body_size' specify the payload for the post.
|
||||
When there is no body, pass in NULL as body_bytes.
|
||||
'deadline' contains a deadline for the request (or gpr_inf_future)
|
||||
'em' points to a caller owned event manager that must be alive for the
|
||||
lifetime of the request
|
||||
'on_response' is a callback to report results to (and 'user_data' is a user
|
||||
supplied pointer to pass to said call)
|
||||
Does not support ?var1=val1&var2=val2 in the path. */
|
||||
void grpc_httpcli_post(const grpc_httpcli_request *request,
|
||||
void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
|
||||
const grpc_httpcli_request *request,
|
||||
const char *body_bytes, size_t body_size,
|
||||
gpr_timespec deadline,
|
||||
grpc_httpcli_response_cb on_response, void *user_data);
|
||||
|
|
@ -115,4 +145,4 @@ typedef int (*grpc_httpcli_post_override)(const grpc_httpcli_request *request,
|
|||
void grpc_httpcli_set_override(grpc_httpcli_get_override get,
|
||||
grpc_httpcli_post_override post);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H */
|
||||
|
|
|
|||
|
|
@ -109,16 +109,40 @@ static void destroy(grpc_fd *fd) {
|
|||
gpr_free(fd);
|
||||
}
|
||||
|
||||
#ifdef GRPC_FD_REF_COUNT_DEBUG
|
||||
#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__)
|
||||
#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
|
||||
static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file,
|
||||
int line) {
|
||||
gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
|
||||
gpr_atm_no_barrier_load(&fd->refst),
|
||||
gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line);
|
||||
#else
|
||||
#define REF_BY(fd, n, reason) ref_by(fd, n)
|
||||
#define UNREF_BY(fd, n, reason) unref_by(fd, n)
|
||||
static void ref_by(grpc_fd *fd, int n) {
|
||||
#endif
|
||||
GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
|
||||
}
|
||||
|
||||
#ifdef GRPC_FD_REF_COUNT_DEBUG
|
||||
static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file,
|
||||
int line) {
|
||||
gpr_atm old;
|
||||
gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
|
||||
gpr_atm_no_barrier_load(&fd->refst),
|
||||
gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line);
|
||||
#else
|
||||
static void unref_by(grpc_fd *fd, int n) {
|
||||
gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
|
||||
gpr_atm old;
|
||||
#endif
|
||||
old = gpr_atm_full_fetch_add(&fd->refst, -n);
|
||||
if (old == n) {
|
||||
grpc_iomgr_add_callback(&fd->on_done_closure);
|
||||
freelist_fd(fd);
|
||||
if (fd->on_done_closure) {
|
||||
grpc_iomgr_add_callback(fd->on_done_closure);
|
||||
}
|
||||
grpc_iomgr_unregister_object(&fd->iomgr_object);
|
||||
freelist_fd(fd);
|
||||
} else {
|
||||
GPR_ASSERT(old > n);
|
||||
}
|
||||
|
|
@ -135,12 +159,9 @@ void grpc_fd_global_shutdown(void) {
|
|||
gpr_mu_destroy(&fd_freelist_mu);
|
||||
}
|
||||
|
||||
static void do_nothing(void *ignored, int success) {}
|
||||
|
||||
grpc_fd *grpc_fd_create(int fd, const char *name) {
|
||||
grpc_fd *r = alloc_fd(fd);
|
||||
grpc_iomgr_register_object(&r->iomgr_object, name);
|
||||
grpc_pollset_add_fd(grpc_backup_pollset(), r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -178,24 +199,35 @@ static void wake_all_watchers_locked(grpc_fd *fd) {
|
|||
}
|
||||
}
|
||||
|
||||
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) {
|
||||
grpc_iomgr_closure_init(&fd->on_done_closure, on_done ? on_done : do_nothing,
|
||||
user_data);
|
||||
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done,
|
||||
const char *reason) {
|
||||
fd->on_done_closure = on_done;
|
||||
shutdown(fd->fd, SHUT_RDWR);
|
||||
ref_by(fd, 1); /* remove active status, but keep referenced */
|
||||
REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
|
||||
gpr_mu_lock(&fd->watcher_mu);
|
||||
wake_all_watchers_locked(fd);
|
||||
gpr_mu_unlock(&fd->watcher_mu);
|
||||
unref_by(fd, 2); /* drop the reference */
|
||||
UNREF_BY(fd, 2, reason); /* drop the reference */
|
||||
}
|
||||
|
||||
/* increment refcount by two to avoid changing the orphan bit */
|
||||
#ifdef GRPC_FD_REF_COUNT_DEBUG
|
||||
void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) {
|
||||
ref_by(fd, 2, reason, file, line);
|
||||
}
|
||||
|
||||
void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file,
|
||||
int line) {
|
||||
unref_by(fd, 2, reason, file, line);
|
||||
}
|
||||
#else
|
||||
void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
|
||||
|
||||
void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
|
||||
#endif
|
||||
|
||||
static void process_callback(grpc_iomgr_closure *closure, int success,
|
||||
int allow_synchronous_callback) {
|
||||
int allow_synchronous_callback) {
|
||||
if (allow_synchronous_callback) {
|
||||
closure->cb(closure->cb_arg, success);
|
||||
} else {
|
||||
|
|
@ -235,7 +267,7 @@ static void notify_on(grpc_fd *fd, gpr_atm *st, grpc_iomgr_closure *closure,
|
|||
GPR_ASSERT(gpr_atm_no_barrier_load(st) == READY);
|
||||
gpr_atm_rel_store(st, NOT_READY);
|
||||
process_callback(closure, !gpr_atm_acq_load(&fd->shutdown),
|
||||
allow_synchronous_callback);
|
||||
allow_synchronous_callback);
|
||||
return;
|
||||
default: /* WAITING */
|
||||
/* upcallptr was set to a different closure. This is an error! */
|
||||
|
|
@ -279,7 +311,7 @@ static void set_ready(grpc_fd *fd, gpr_atm *st,
|
|||
/* only one set_ready can be active at once (but there may be a racing
|
||||
notify_on) */
|
||||
int success;
|
||||
grpc_iomgr_closure* closure;
|
||||
grpc_iomgr_closure *closure;
|
||||
size_t ncb = 0;
|
||||
|
||||
gpr_mu_lock(&fd->set_state_mu);
|
||||
|
|
@ -319,7 +351,7 @@ gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
|
|||
gpr_uint32 mask = 0;
|
||||
/* keep track of pollers that have requested our events, in case they change
|
||||
*/
|
||||
grpc_fd_ref(fd);
|
||||
GRPC_FD_REF(fd, "poll");
|
||||
|
||||
gpr_mu_lock(&fd->watcher_mu);
|
||||
/* if there is nobody polling for read, but we need to, then start doing so */
|
||||
|
|
@ -374,7 +406,7 @@ void grpc_fd_end_poll(grpc_fd_watcher *watcher, int got_read, int got_write) {
|
|||
}
|
||||
gpr_mu_unlock(&fd->watcher_mu);
|
||||
|
||||
grpc_fd_unref(fd);
|
||||
GRPC_FD_UNREF(fd, "poll");
|
||||
}
|
||||
|
||||
void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback) {
|
||||
|
|
|
|||
|
|
@ -62,12 +62,12 @@ struct grpc_fd {
|
|||
gpr_atm shutdown;
|
||||
|
||||
/* The watcher list.
|
||||
|
||||
|
||||
The following watcher related fields are protected by watcher_mu.
|
||||
|
||||
|
||||
An fd_watcher is an ephemeral object created when an fd wants to
|
||||
begin polling, and destroyed after the poll.
|
||||
|
||||
|
||||
It denotes the fd's interest in whether to read poll or write poll
|
||||
or both or neither on this fd.
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ struct grpc_fd {
|
|||
|
||||
struct grpc_fd *freelist_next;
|
||||
|
||||
grpc_iomgr_closure on_done_closure;
|
||||
grpc_iomgr_closure *on_done_closure;
|
||||
grpc_iomgr_closure *shutdown_closures[2];
|
||||
|
||||
grpc_iomgr_object iomgr_object;
|
||||
|
|
@ -109,7 +109,8 @@ grpc_fd *grpc_fd_create(int fd, const char *name);
|
|||
If on_done is NULL, no callback will be made.
|
||||
Requires: *fd initialized; no outstanding notify_on_read or
|
||||
notify_on_write. */
|
||||
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data);
|
||||
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done,
|
||||
const char *reason);
|
||||
|
||||
/* Begin polling on an fd.
|
||||
Registers that the given pollset is interested in this fd - so that if read
|
||||
|
|
@ -159,10 +160,19 @@ void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback);
|
|||
void grpc_fd_become_writable(grpc_fd *fd, int allow_synchronous_callback);
|
||||
|
||||
/* Reference counting for fds */
|
||||
#ifdef GRPC_FD_REF_COUNT_DEBUG
|
||||
void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line);
|
||||
void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line);
|
||||
#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd, reason, __FILE__, __LINE__)
|
||||
#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd, reason, __FILE__, __LINE__)
|
||||
#else
|
||||
void grpc_fd_ref(grpc_fd *fd);
|
||||
void grpc_fd_unref(grpc_fd *fd);
|
||||
#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd)
|
||||
#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd)
|
||||
#endif
|
||||
|
||||
void grpc_fd_global_init(void);
|
||||
void grpc_fd_global_shutdown(void);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H */
|
||||
|
|
|
|||
|
|
@ -112,13 +112,20 @@ void grpc_iomgr_shutdown(void) {
|
|||
gpr_timespec shutdown_deadline =
|
||||
gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
|
||||
|
||||
|
||||
gpr_mu_lock(&g_mu);
|
||||
g_shutdown = 1;
|
||||
while (g_cbs_head || g_root_object.next != &g_root_object) {
|
||||
size_t nobjs = count_objects();
|
||||
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", nobjs,
|
||||
g_cbs_head ? " and executing final callbacks" : "");
|
||||
while (g_cbs_head != NULL || g_root_object.next != &g_root_object) {
|
||||
if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
|
||||
gpr_log(GPR_DEBUG,
|
||||
"Waiting for %d iomgr objects to be destroyed and executing "
|
||||
"final callbacks",
|
||||
count_objects());
|
||||
} else if (g_cbs_head != NULL) {
|
||||
gpr_log(GPR_DEBUG, "Executing final iomgr callbacks");
|
||||
} else {
|
||||
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
|
||||
count_objects());
|
||||
}
|
||||
if (g_cbs_head) {
|
||||
do {
|
||||
closure = g_cbs_head;
|
||||
|
|
@ -131,10 +138,14 @@ void grpc_iomgr_shutdown(void) {
|
|||
} while (g_cbs_head);
|
||||
continue;
|
||||
}
|
||||
if (nobjs > 0) {
|
||||
if (grpc_alarm_check(&g_mu, gpr_inf_future, NULL)) {
|
||||
gpr_log(GPR_DEBUG, "got late alarm");
|
||||
continue;
|
||||
}
|
||||
if (g_root_object.next != &g_root_object) {
|
||||
int timeout = 0;
|
||||
gpr_timespec short_deadline = gpr_time_add(gpr_now(),
|
||||
gpr_time_from_millis(100));
|
||||
gpr_timespec short_deadline =
|
||||
gpr_time_add(gpr_now(), gpr_time_from_millis(100));
|
||||
while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
|
||||
if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
|
||||
timeout = 1;
|
||||
|
|
@ -158,15 +169,16 @@ void grpc_iomgr_shutdown(void) {
|
|||
grpc_kick_poller();
|
||||
gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future);
|
||||
|
||||
grpc_iomgr_platform_shutdown();
|
||||
grpc_alarm_list_shutdown();
|
||||
|
||||
grpc_iomgr_platform_shutdown();
|
||||
gpr_mu_destroy(&g_mu);
|
||||
gpr_cv_destroy(&g_rcv);
|
||||
}
|
||||
|
||||
void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
|
||||
obj->name = gpr_strdup(name);
|
||||
gpr_mu_lock(&g_mu);
|
||||
obj->name = gpr_strdup(name);
|
||||
obj->next = &g_root_object;
|
||||
obj->prev = obj->next->prev;
|
||||
obj->next->prev = obj->prev->next = obj;
|
||||
|
|
@ -174,15 +186,14 @@ void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
|
|||
}
|
||||
|
||||
void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
|
||||
gpr_free(obj->name);
|
||||
gpr_mu_lock(&g_mu);
|
||||
obj->next->prev = obj->prev;
|
||||
obj->prev->next = obj->next;
|
||||
gpr_free(obj->name);
|
||||
gpr_cv_signal(&g_rcv);
|
||||
gpr_mu_unlock(&g_mu);
|
||||
}
|
||||
|
||||
|
||||
void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
|
||||
void *cb_arg) {
|
||||
closure->cb = cb;
|
||||
|
|
@ -200,15 +211,16 @@ void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *closure, int success) {
|
|||
g_cbs_tail->next = closure;
|
||||
g_cbs_tail = closure;
|
||||
}
|
||||
if (g_shutdown) {
|
||||
gpr_cv_signal(&g_rcv);
|
||||
}
|
||||
gpr_mu_unlock(&g_mu);
|
||||
}
|
||||
|
||||
|
||||
void grpc_iomgr_add_callback(grpc_iomgr_closure *closure) {
|
||||
grpc_iomgr_add_delayed_callback(closure, 1 /* GPR_TRUE */);
|
||||
}
|
||||
|
||||
|
||||
int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) {
|
||||
int n = 0;
|
||||
gpr_mu *retake_mu = NULL;
|
||||
|
|
|
|||
|
|
@ -52,14 +52,12 @@
|
|||
#include "src/core/iomgr/pollset_windows.h"
|
||||
#endif
|
||||
|
||||
|
||||
void grpc_pollset_init(grpc_pollset *pollset);
|
||||
void grpc_pollset_shutdown(grpc_pollset *pollset,
|
||||
void (*shutdown_done)(void *arg),
|
||||
void *shutdown_done_arg);
|
||||
void grpc_pollset_destroy(grpc_pollset *pollset);
|
||||
|
||||
|
||||
/* Do some work on a pollset.
|
||||
May involve invoking asynchronous callbacks, or actually polling file
|
||||
descriptors.
|
||||
|
|
@ -67,8 +65,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
|
|||
May unlock GRPC_POLLSET_MU(pollset) during its execution. */
|
||||
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline);
|
||||
|
||||
/* Break a pollset out of polling work
|
||||
/* Break one polling thread out of polling work for this pollset.
|
||||
Requires GRPC_POLLSET_MU(pollset) locked. */
|
||||
void grpc_pollset_kick(grpc_pollset *pollset);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#ifdef GPR_POSIX_SOCKET
|
||||
#include "src/core/iomgr/pollset_kick.h"
|
||||
#include "src/core/iomgr/pollset_kick_posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
|
@ -73,7 +73,7 @@ static grpc_kick_fd_info *allocate_wfd(void) {
|
|||
return info;
|
||||
}
|
||||
|
||||
static void destroy_wfd(grpc_kick_fd_info* wfd) {
|
||||
static void destroy_wfd(grpc_kick_fd_info *wfd) {
|
||||
grpc_wakeup_fd_destroy(&wfd->wakeup_fd);
|
||||
gpr_free(wfd);
|
||||
}
|
||||
|
|
@ -96,41 +96,49 @@ static void free_wfd(grpc_kick_fd_info *fd_info) {
|
|||
void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state) {
|
||||
gpr_mu_init(&kick_state->mu);
|
||||
kick_state->kicked = 0;
|
||||
kick_state->fd_info = NULL;
|
||||
kick_state->fd_list.next = kick_state->fd_list.prev = &kick_state->fd_list;
|
||||
}
|
||||
|
||||
void grpc_pollset_kick_destroy(grpc_pollset_kick_state *kick_state) {
|
||||
gpr_mu_destroy(&kick_state->mu);
|
||||
GPR_ASSERT(kick_state->fd_info == NULL);
|
||||
GPR_ASSERT(kick_state->fd_list.next == &kick_state->fd_list);
|
||||
}
|
||||
|
||||
int grpc_pollset_kick_pre_poll(grpc_pollset_kick_state *kick_state) {
|
||||
grpc_kick_fd_info *grpc_pollset_kick_pre_poll(
|
||||
grpc_pollset_kick_state *kick_state) {
|
||||
grpc_kick_fd_info *fd_info;
|
||||
gpr_mu_lock(&kick_state->mu);
|
||||
if (kick_state->kicked) {
|
||||
kick_state->kicked = 0;
|
||||
gpr_mu_unlock(&kick_state->mu);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
kick_state->fd_info = allocate_wfd();
|
||||
fd_info = allocate_wfd();
|
||||
fd_info->next = &kick_state->fd_list;
|
||||
fd_info->prev = fd_info->next->prev;
|
||||
fd_info->next->prev = fd_info->prev->next = fd_info;
|
||||
gpr_mu_unlock(&kick_state->mu);
|
||||
return GRPC_WAKEUP_FD_GET_READ_FD(&kick_state->fd_info->wakeup_fd);
|
||||
return fd_info;
|
||||
}
|
||||
|
||||
void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state) {
|
||||
grpc_wakeup_fd_consume_wakeup(&kick_state->fd_info->wakeup_fd);
|
||||
void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state,
|
||||
grpc_kick_fd_info *fd_info) {
|
||||
grpc_wakeup_fd_consume_wakeup(&fd_info->wakeup_fd);
|
||||
}
|
||||
|
||||
void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state) {
|
||||
void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state,
|
||||
grpc_kick_fd_info *fd_info) {
|
||||
gpr_mu_lock(&kick_state->mu);
|
||||
free_wfd(kick_state->fd_info);
|
||||
kick_state->fd_info = NULL;
|
||||
fd_info->next->prev = fd_info->prev;
|
||||
fd_info->prev->next = fd_info->next;
|
||||
free_wfd(fd_info);
|
||||
gpr_mu_unlock(&kick_state->mu);
|
||||
}
|
||||
|
||||
void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state) {
|
||||
gpr_mu_lock(&kick_state->mu);
|
||||
if (kick_state->fd_info != NULL) {
|
||||
grpc_wakeup_fd_wakeup(&kick_state->fd_info->wakeup_fd);
|
||||
if (kick_state->fd_list.next != &kick_state->fd_list) {
|
||||
grpc_wakeup_fd_wakeup(&kick_state->fd_list.next->wakeup_fd);
|
||||
} else {
|
||||
kick_state->kicked = 1;
|
||||
}
|
||||
|
|
@ -157,5 +165,4 @@ void grpc_pollset_kick_global_destroy(void) {
|
|||
gpr_mu_destroy(&fd_freelist_mu);
|
||||
}
|
||||
|
||||
|
||||
#endif /* GPR_POSIX_SOCKET */
|
||||
#endif /* GPR_POSIX_SOCKET */
|
||||
|
|
@ -37,15 +37,57 @@
|
|||
#include "src/core/iomgr/wakeup_fd_posix.h"
|
||||
#include <grpc/support/sync.h>
|
||||
|
||||
/* pollset kicking allows breaking a thread out of polling work for
|
||||
a given pollset.
|
||||
writing a byte to a pipe is used as a posix-ly portable base
|
||||
mechanism, and eventfds are utilized on Linux for better performance. */
|
||||
|
||||
typedef struct grpc_kick_fd_info {
|
||||
grpc_wakeup_fd_info wakeup_fd;
|
||||
/* used for polling list and free list */
|
||||
struct grpc_kick_fd_info *next;
|
||||
/* only used when polling */
|
||||
struct grpc_kick_fd_info *prev;
|
||||
} grpc_kick_fd_info;
|
||||
|
||||
typedef struct grpc_pollset_kick_state {
|
||||
gpr_mu mu;
|
||||
int kicked;
|
||||
struct grpc_kick_fd_info *fd_info;
|
||||
struct grpc_kick_fd_info fd_list;
|
||||
} grpc_pollset_kick_state;
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_POSIX_H */
|
||||
#define GRPC_POLLSET_KICK_GET_FD(kick_fd_info) \
|
||||
GRPC_WAKEUP_FD_GET_READ_FD(&(kick_fd_info)->wakeup_fd)
|
||||
|
||||
/* This is an abstraction around the typical pipe mechanism for waking up a
|
||||
thread sitting in a poll() style call. */
|
||||
|
||||
void grpc_pollset_kick_global_init(void);
|
||||
void grpc_pollset_kick_global_destroy(void);
|
||||
|
||||
void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state);
|
||||
void grpc_pollset_kick_destroy(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
/* Guarantees a pure posix implementation rather than a specialized one, if
|
||||
* applicable. Intended for testing. */
|
||||
void grpc_pollset_kick_global_init_fallback_fd(void);
|
||||
|
||||
/* Must be called before entering poll(). If return value is NULL, this consumed
|
||||
an existing kick. Otherwise the return value is an FD to add to the poll set.
|
||||
*/
|
||||
grpc_kick_fd_info *grpc_pollset_kick_pre_poll(
|
||||
grpc_pollset_kick_state *kick_state);
|
||||
|
||||
/* Consume an existing kick. Must be called after poll returns that the fd was
|
||||
readable, and before calling kick_post_poll. */
|
||||
void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state,
|
||||
grpc_kick_fd_info *fd_info);
|
||||
|
||||
/* Must be called after pre_poll, and after consume if applicable */
|
||||
void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state,
|
||||
grpc_kick_fd_info *fd_info);
|
||||
|
||||
/* Actually kick */
|
||||
void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_POSIX_H */
|
||||
|
|
|
|||
|
|
@ -97,14 +97,7 @@ static int multipoll_with_epoll_pollset_maybe_work(
|
|||
* here.
|
||||
*/
|
||||
|
||||
if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
|
||||
timeout_ms = -1;
|
||||
} else {
|
||||
timeout_ms = gpr_time_to_millis(gpr_time_sub(deadline, now));
|
||||
if (timeout_ms <= 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
|
||||
pollset->counter += 1;
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
|
||||
|
|
@ -140,13 +133,12 @@ static int multipoll_with_epoll_pollset_maybe_work(
|
|||
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
pollset->counter -= 1;
|
||||
/* TODO(klempner): This should signal once per event rather than broadcast,
|
||||
* although it probably doesn't matter because threads will generally be
|
||||
* blocked in epoll_wait rather than being blocked on the cv. */
|
||||
gpr_cv_broadcast(&pollset->cv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void multipoll_with_epoll_pollset_finish_shutdown(
|
||||
grpc_pollset *pollset) {}
|
||||
|
||||
static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
|
||||
pollset_hdr *h = pollset->data.ptr;
|
||||
grpc_wakeup_fd_destroy(&h->wakeup_fd);
|
||||
|
|
@ -160,8 +152,11 @@ static void epoll_kick(grpc_pollset *pollset) {
|
|||
}
|
||||
|
||||
static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
|
||||
multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd,
|
||||
multipoll_with_epoll_pollset_maybe_work, epoll_kick,
|
||||
multipoll_with_epoll_pollset_add_fd,
|
||||
multipoll_with_epoll_pollset_del_fd,
|
||||
multipoll_with_epoll_pollset_maybe_work,
|
||||
epoll_kick,
|
||||
multipoll_with_epoll_pollset_finish_shutdown,
|
||||
multipoll_with_epoll_pollset_destroy};
|
||||
|
||||
static void epoll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset,
|
|||
h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity);
|
||||
}
|
||||
h->fds[h->fd_count++] = fd;
|
||||
grpc_fd_ref(fd);
|
||||
GRPC_FD_REF(fd, "multipoller");
|
||||
}
|
||||
|
||||
static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset,
|
||||
|
|
@ -90,7 +90,7 @@ static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset,
|
|||
h->dels = gpr_realloc(h->dels, sizeof(grpc_fd *) * h->del_capacity);
|
||||
}
|
||||
h->dels[h->del_count++] = fd;
|
||||
grpc_fd_ref(fd);
|
||||
GRPC_FD_REF(fd, "multipoller_del");
|
||||
}
|
||||
|
||||
static void end_polling(grpc_pollset *pollset) {
|
||||
|
|
@ -110,19 +110,10 @@ static int multipoll_with_poll_pollset_maybe_work(
|
|||
int r;
|
||||
size_t i, np, nf, nd;
|
||||
pollset_hdr *h;
|
||||
grpc_kick_fd_info *kfd;
|
||||
|
||||
if (pollset->counter) {
|
||||
return 0;
|
||||
}
|
||||
h = pollset->data.ptr;
|
||||
if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
|
||||
timeout = -1;
|
||||
} else {
|
||||
timeout = gpr_time_to_millis(gpr_time_sub(deadline, now));
|
||||
if (timeout <= 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
|
||||
if (h->pfd_capacity < h->fd_count + 1) {
|
||||
h->pfd_capacity = GPR_MAX(h->pfd_capacity * 3 / 2, h->fd_count + 1);
|
||||
gpr_free(h->pfds);
|
||||
|
|
@ -132,11 +123,12 @@ static int multipoll_with_poll_pollset_maybe_work(
|
|||
}
|
||||
nf = 0;
|
||||
np = 1;
|
||||
h->pfds[0].fd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
|
||||
if (h->pfds[0].fd < 0) {
|
||||
kfd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
|
||||
if (kfd == NULL) {
|
||||
/* Already kicked */
|
||||
return 1;
|
||||
}
|
||||
h->pfds[0].fd = GRPC_POLLSET_KICK_GET_FD(kfd);
|
||||
h->pfds[0].events = POLLIN;
|
||||
h->pfds[0].revents = POLLOUT;
|
||||
for (i = 0; i < h->fd_count; i++) {
|
||||
|
|
@ -145,7 +137,7 @@ static int multipoll_with_poll_pollset_maybe_work(
|
|||
if (h->fds[i] == h->dels[nd]) remove = 1;
|
||||
}
|
||||
if (remove) {
|
||||
grpc_fd_unref(h->fds[i]);
|
||||
GRPC_FD_UNREF(h->fds[i], "multipoller");
|
||||
} else {
|
||||
h->fds[nf++] = h->fds[i];
|
||||
h->watchers[np].fd = h->fds[i];
|
||||
|
|
@ -157,14 +149,14 @@ static int multipoll_with_poll_pollset_maybe_work(
|
|||
h->pfd_count = np;
|
||||
h->fd_count = nf;
|
||||
for (nd = 0; nd < h->del_count; nd++) {
|
||||
grpc_fd_unref(h->dels[nd]);
|
||||
GRPC_FD_UNREF(h->dels[nd], "multipoller_del");
|
||||
}
|
||||
h->del_count = 0;
|
||||
if (h->pfd_count == 0) {
|
||||
end_polling(pollset);
|
||||
return 0;
|
||||
}
|
||||
pollset->counter = 1;
|
||||
pollset->counter++;
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
|
||||
for (i = 1; i < np; i++) {
|
||||
|
|
@ -184,7 +176,7 @@ static int multipoll_with_poll_pollset_maybe_work(
|
|||
/* do nothing */
|
||||
} else {
|
||||
if (h->pfds[0].revents & POLLIN) {
|
||||
grpc_pollset_kick_consume(&pollset->kick_state);
|
||||
grpc_pollset_kick_consume(&pollset->kick_state, kfd);
|
||||
}
|
||||
for (i = 1; i < np; i++) {
|
||||
if (h->pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
|
||||
|
|
@ -195,11 +187,11 @@ static int multipoll_with_poll_pollset_maybe_work(
|
|||
}
|
||||
}
|
||||
}
|
||||
grpc_pollset_kick_post_poll(&pollset->kick_state);
|
||||
grpc_pollset_kick_post_poll(&pollset->kick_state, kfd);
|
||||
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
pollset->counter = 0;
|
||||
gpr_cv_broadcast(&pollset->cv);
|
||||
pollset->counter--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -207,16 +199,23 @@ static void multipoll_with_poll_pollset_kick(grpc_pollset *p) {
|
|||
grpc_pollset_force_kick(p);
|
||||
}
|
||||
|
||||
static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
|
||||
static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
|
||||
size_t i;
|
||||
pollset_hdr *h = pollset->data.ptr;
|
||||
GPR_ASSERT(pollset->counter == 0);
|
||||
for (i = 0; i < h->fd_count; i++) {
|
||||
grpc_fd_unref(h->fds[i]);
|
||||
GRPC_FD_UNREF(h->fds[i], "multipoller");
|
||||
}
|
||||
for (i = 0; i < h->del_count; i++) {
|
||||
grpc_fd_unref(h->dels[i]);
|
||||
GRPC_FD_UNREF(h->dels[i], "multipoller_del");
|
||||
}
|
||||
h->fd_count = 0;
|
||||
h->del_count = 0;
|
||||
}
|
||||
|
||||
static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
|
||||
pollset_hdr *h = pollset->data.ptr;
|
||||
multipoll_with_poll_pollset_finish_shutdown(pollset);
|
||||
gpr_free(h->pfds);
|
||||
gpr_free(h->watchers);
|
||||
gpr_free(h->fds);
|
||||
|
|
@ -225,8 +224,11 @@ static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
|
|||
}
|
||||
|
||||
static const grpc_pollset_vtable multipoll_with_poll_pollset = {
|
||||
multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd,
|
||||
multipoll_with_poll_pollset_maybe_work, multipoll_with_poll_pollset_kick,
|
||||
multipoll_with_poll_pollset_add_fd,
|
||||
multipoll_with_poll_pollset_del_fd,
|
||||
multipoll_with_poll_pollset_maybe_work,
|
||||
multipoll_with_poll_pollset_kick,
|
||||
multipoll_with_poll_pollset_finish_shutdown,
|
||||
multipoll_with_poll_pollset_destroy};
|
||||
|
||||
void grpc_poll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
|
||||
|
|
@ -247,7 +249,7 @@ void grpc_poll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
|
|||
h->dels = NULL;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
h->fds[i] = fds[i];
|
||||
grpc_fd_ref(fds[i]);
|
||||
GRPC_FD_REF(fds[i], "multipoller");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,31 +54,8 @@
|
|||
#include <grpc/support/tls.h>
|
||||
#include <grpc/support/useful.h>
|
||||
|
||||
static grpc_pollset g_backup_pollset;
|
||||
static int g_shutdown_backup_poller;
|
||||
static gpr_event g_backup_poller_done;
|
||||
static gpr_event g_backup_pollset_shutdown_done;
|
||||
|
||||
GPR_TLS_DECL(g_current_thread_poller);
|
||||
|
||||
static void backup_poller(void *p) {
|
||||
gpr_timespec delta = gpr_time_from_millis(100);
|
||||
gpr_timespec last_poll = gpr_now();
|
||||
|
||||
gpr_mu_lock(&g_backup_pollset.mu);
|
||||
while (g_shutdown_backup_poller == 0) {
|
||||
gpr_timespec next_poll = gpr_time_add(last_poll, delta);
|
||||
grpc_pollset_work(&g_backup_pollset, gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
|
||||
gpr_mu_unlock(&g_backup_pollset.mu);
|
||||
gpr_sleep_until(next_poll);
|
||||
gpr_mu_lock(&g_backup_pollset.mu);
|
||||
last_poll = next_poll;
|
||||
}
|
||||
gpr_mu_unlock(&g_backup_pollset.mu);
|
||||
|
||||
gpr_event_set(&g_backup_poller_done, (void *)1);
|
||||
}
|
||||
|
||||
void grpc_pollset_kick(grpc_pollset *p) {
|
||||
if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p && p->counter) {
|
||||
p->vtable->kick(p);
|
||||
|
|
@ -99,44 +76,14 @@ static void kick_using_pollset_kick(grpc_pollset *p) {
|
|||
|
||||
/* global state management */
|
||||
|
||||
grpc_pollset *grpc_backup_pollset(void) { return &g_backup_pollset; }
|
||||
|
||||
void grpc_pollset_global_init(void) {
|
||||
gpr_thd_id id;
|
||||
|
||||
gpr_tls_init(&g_current_thread_poller);
|
||||
|
||||
/* Initialize kick fd state */
|
||||
grpc_pollset_kick_global_init();
|
||||
|
||||
/* initialize the backup pollset */
|
||||
grpc_pollset_init(&g_backup_pollset);
|
||||
|
||||
/* start the backup poller thread */
|
||||
g_shutdown_backup_poller = 0;
|
||||
gpr_event_init(&g_backup_poller_done);
|
||||
gpr_event_init(&g_backup_pollset_shutdown_done);
|
||||
gpr_thd_new(&id, backup_poller, NULL, NULL);
|
||||
}
|
||||
|
||||
static void on_backup_pollset_shutdown_done(void *arg) {
|
||||
gpr_event_set(&g_backup_pollset_shutdown_done, (void *)1);
|
||||
}
|
||||
|
||||
void grpc_pollset_global_shutdown(void) {
|
||||
/* terminate the backup poller thread */
|
||||
gpr_mu_lock(&g_backup_pollset.mu);
|
||||
g_shutdown_backup_poller = 1;
|
||||
gpr_mu_unlock(&g_backup_pollset.mu);
|
||||
gpr_event_wait(&g_backup_poller_done, gpr_inf_future);
|
||||
|
||||
grpc_pollset_shutdown(&g_backup_pollset, on_backup_pollset_shutdown_done,
|
||||
NULL);
|
||||
gpr_event_wait(&g_backup_pollset_shutdown_done, gpr_inf_future);
|
||||
|
||||
/* destroy the backup pollset */
|
||||
grpc_pollset_destroy(&g_backup_pollset);
|
||||
|
||||
/* destroy the kick pipes */
|
||||
grpc_pollset_kick_global_destroy();
|
||||
|
||||
|
|
@ -145,37 +92,37 @@ void grpc_pollset_global_shutdown(void) {
|
|||
|
||||
/* main interface */
|
||||
|
||||
static void become_empty_pollset(grpc_pollset *pollset);
|
||||
static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd);
|
||||
static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null);
|
||||
|
||||
void grpc_pollset_init(grpc_pollset *pollset) {
|
||||
gpr_mu_init(&pollset->mu);
|
||||
gpr_cv_init(&pollset->cv);
|
||||
grpc_pollset_kick_init(&pollset->kick_state);
|
||||
pollset->in_flight_cbs = 0;
|
||||
pollset->shutting_down = 0;
|
||||
become_empty_pollset(pollset);
|
||||
pollset->called_shutdown = 0;
|
||||
become_basic_pollset(pollset, NULL);
|
||||
}
|
||||
|
||||
void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
pollset->vtable->add_fd(pollset, fd);
|
||||
gpr_cv_broadcast(&pollset->cv);
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
}
|
||||
|
||||
void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
pollset->vtable->del_fd(pollset, fd);
|
||||
gpr_cv_broadcast(&pollset->cv);
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
}
|
||||
|
||||
static void finish_shutdown(grpc_pollset *pollset) {
|
||||
pollset->vtable->finish_shutdown(pollset);
|
||||
pollset->shutdown_done_cb(pollset->shutdown_done_arg);
|
||||
}
|
||||
|
||||
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
|
||||
/* pollset->mu already held */
|
||||
gpr_timespec now = gpr_now();
|
||||
/* FIXME(ctiller): see below */
|
||||
gpr_timespec maximum_deadline = gpr_time_add(now, gpr_time_from_seconds(1));
|
||||
int r;
|
||||
if (gpr_time_cmp(now, deadline) > 0) {
|
||||
return 0;
|
||||
|
|
@ -186,29 +133,50 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
|
|||
if (grpc_alarm_check(&pollset->mu, now, &deadline)) {
|
||||
return 1;
|
||||
}
|
||||
/* FIXME(ctiller): we should not clamp deadline, however we have some
|
||||
stuck at shutdown bugs that this resolves */
|
||||
if (gpr_time_cmp(deadline, maximum_deadline) > 0) {
|
||||
deadline = maximum_deadline;
|
||||
if (pollset->shutting_down) {
|
||||
return 1;
|
||||
}
|
||||
gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset);
|
||||
r = pollset->vtable->maybe_work(pollset, deadline, now, 1);
|
||||
gpr_tls_set(&g_current_thread_poller, 0);
|
||||
if (pollset->shutting_down) {
|
||||
if (pollset->counter > 0) {
|
||||
grpc_pollset_kick(pollset);
|
||||
} else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) {
|
||||
pollset->called_shutdown = 1;
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
finish_shutdown(pollset);
|
||||
/* Continuing to access pollset here is safe -- it is the caller's
|
||||
* responsibility to not destroy when it has outstanding calls to
|
||||
* grpc_pollset_work.
|
||||
* TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void grpc_pollset_shutdown(grpc_pollset *pollset,
|
||||
void (*shutdown_done)(void *arg),
|
||||
void *shutdown_done_arg) {
|
||||
int in_flight_cbs;
|
||||
int call_shutdown = 0;
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
GPR_ASSERT(!pollset->shutting_down);
|
||||
pollset->shutting_down = 1;
|
||||
in_flight_cbs = pollset->in_flight_cbs;
|
||||
if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 &&
|
||||
pollset->counter == 0) {
|
||||
pollset->called_shutdown = 1;
|
||||
call_shutdown = 1;
|
||||
}
|
||||
pollset->shutdown_done_cb = shutdown_done;
|
||||
pollset->shutdown_done_arg = shutdown_done_arg;
|
||||
if (pollset->counter > 0) {
|
||||
grpc_pollset_kick(pollset);
|
||||
}
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
if (in_flight_cbs == 0) {
|
||||
shutdown_done(shutdown_done_arg);
|
||||
|
||||
if (call_shutdown) {
|
||||
finish_shutdown(pollset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,41 +186,29 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
|
|||
pollset->vtable->destroy(pollset);
|
||||
grpc_pollset_kick_destroy(&pollset->kick_state);
|
||||
gpr_mu_destroy(&pollset->mu);
|
||||
gpr_cv_destroy(&pollset->cv);
|
||||
}
|
||||
|
||||
int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now) {
|
||||
gpr_timespec timeout;
|
||||
static const int max_spin_polling_us = 10;
|
||||
if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (gpr_time_cmp(
|
||||
deadline,
|
||||
gpr_time_add(now, gpr_time_from_micros(max_spin_polling_us))) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
timeout = gpr_time_sub(deadline, now);
|
||||
return gpr_time_to_millis(
|
||||
gpr_time_add(timeout, gpr_time_from_nanos(GPR_NS_PER_SEC - 1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* empty_pollset - a vtable that provides polling for NO file descriptors
|
||||
* basic_pollset - a vtable that provides polling for zero or one file
|
||||
* descriptor via poll()
|
||||
*/
|
||||
|
||||
static void empty_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
become_unary_pollset(pollset, fd);
|
||||
}
|
||||
|
||||
static void empty_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {}
|
||||
|
||||
static int empty_pollset_maybe_work(grpc_pollset *pollset,
|
||||
gpr_timespec deadline, gpr_timespec now,
|
||||
int allow_synchronous_callback) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void empty_pollset_destroy(grpc_pollset *pollset) {}
|
||||
|
||||
static const grpc_pollset_vtable empty_pollset = {
|
||||
empty_pollset_add_fd, empty_pollset_del_fd, empty_pollset_maybe_work,
|
||||
kick_using_pollset_kick, empty_pollset_destroy};
|
||||
|
||||
static void become_empty_pollset(grpc_pollset *pollset) {
|
||||
pollset->vtable = &empty_pollset;
|
||||
}
|
||||
|
||||
/*
|
||||
* unary_poll_pollset - a vtable that provides polling for one file descriptor
|
||||
* via poll()
|
||||
*/
|
||||
|
||||
|
||||
typedef struct grpc_unary_promote_args {
|
||||
const grpc_pollset_vtable *original_vtable;
|
||||
grpc_pollset *pollset;
|
||||
|
|
@ -260,7 +216,7 @@ typedef struct grpc_unary_promote_args {
|
|||
grpc_iomgr_closure promotion_closure;
|
||||
} grpc_unary_promote_args;
|
||||
|
||||
static void unary_poll_do_promote(void *args, int success) {
|
||||
static void basic_do_promote(void *args, int success) {
|
||||
grpc_unary_promote_args *up_args = args;
|
||||
const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
|
||||
grpc_pollset *pollset = up_args->pollset;
|
||||
|
|
@ -278,7 +234,7 @@ static void unary_poll_do_promote(void *args, int success) {
|
|||
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
/* First we need to ensure that nobody is polling concurrently */
|
||||
while (pollset->counter != 0) {
|
||||
if (pollset->counter != 0) {
|
||||
grpc_pollset_kick(pollset);
|
||||
grpc_iomgr_add_callback(&up_args->promotion_closure);
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
|
|
@ -294,7 +250,7 @@ static void unary_poll_do_promote(void *args, int success) {
|
|||
pollset->in_flight_cbs--;
|
||||
if (pollset->shutting_down) {
|
||||
/* We don't care about this pollset anymore. */
|
||||
if (pollset->in_flight_cbs == 0) {
|
||||
if (pollset->in_flight_cbs == 0 && pollset->counter == 0) {
|
||||
do_shutdown_cb = 1;
|
||||
}
|
||||
} else if (grpc_fd_is_orphaned(fd)) {
|
||||
|
|
@ -306,33 +262,33 @@ static void unary_poll_do_promote(void *args, int success) {
|
|||
fds[0] = pollset->data.ptr;
|
||||
fds[1] = fd;
|
||||
|
||||
if (!grpc_fd_is_orphaned(fds[0])) {
|
||||
if (fds[0] && !grpc_fd_is_orphaned(fds[0])) {
|
||||
grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds));
|
||||
grpc_fd_unref(fds[0]);
|
||||
GRPC_FD_UNREF(fds[0], "basicpoll");
|
||||
} else {
|
||||
/* old fd is orphaned and we haven't cleaned it up until now, so remain a
|
||||
* unary poller */
|
||||
/* Note that it is possible that fds[1] is also orphaned at this point.
|
||||
* That's okay, we'll correct it at the next add or poll. */
|
||||
grpc_fd_unref(fds[0]);
|
||||
if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll");
|
||||
pollset->data.ptr = fd;
|
||||
grpc_fd_ref(fd);
|
||||
GRPC_FD_REF(fd, "basicpoll");
|
||||
}
|
||||
}
|
||||
|
||||
gpr_cv_broadcast(&pollset->cv);
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
|
||||
if (do_shutdown_cb) {
|
||||
pollset->shutdown_done_cb(pollset->shutdown_done_arg);
|
||||
}
|
||||
|
||||
/* Matching ref in unary_poll_pollset_add_fd */
|
||||
grpc_fd_unref(fd);
|
||||
/* Matching ref in basic_pollset_add_fd */
|
||||
GRPC_FD_UNREF(fd, "basicpoll_add");
|
||||
}
|
||||
|
||||
static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
grpc_unary_promote_args *up_args;
|
||||
GPR_ASSERT(fd);
|
||||
if (fd == pollset->data.ptr) return;
|
||||
|
||||
if (!pollset->counter) {
|
||||
|
|
@ -343,92 +299,100 @@ static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
|||
fds[0] = pollset->data.ptr;
|
||||
fds[1] = fd;
|
||||
|
||||
if (!grpc_fd_is_orphaned(fds[0])) {
|
||||
if (fds[0] == NULL) {
|
||||
pollset->data.ptr = fd;
|
||||
GRPC_FD_REF(fd, "basicpoll");
|
||||
} else if (!grpc_fd_is_orphaned(fds[0])) {
|
||||
grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds));
|
||||
grpc_fd_unref(fds[0]);
|
||||
GRPC_FD_UNREF(fds[0], "basicpoll");
|
||||
} else {
|
||||
/* old fd is orphaned and we haven't cleaned it up until now, so remain a
|
||||
* unary poller */
|
||||
grpc_fd_unref(fds[0]);
|
||||
GRPC_FD_UNREF(fds[0], "basicpoll");
|
||||
pollset->data.ptr = fd;
|
||||
grpc_fd_ref(fd);
|
||||
GRPC_FD_REF(fd, "basicpoll");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we need to promote. This needs to happen when we're not polling. Since
|
||||
* this may be called from poll, the wait needs to happen asynchronously. */
|
||||
grpc_fd_ref(fd);
|
||||
GRPC_FD_REF(fd, "basicpoll_add");
|
||||
pollset->in_flight_cbs++;
|
||||
up_args = gpr_malloc(sizeof(*up_args));
|
||||
up_args->pollset = pollset;
|
||||
up_args->fd = fd;
|
||||
up_args->original_vtable = pollset->vtable;
|
||||
up_args->promotion_closure.cb = unary_poll_do_promote;
|
||||
up_args->promotion_closure.cb = basic_do_promote;
|
||||
up_args->promotion_closure.cb_arg = up_args;
|
||||
grpc_iomgr_add_callback(&up_args->promotion_closure);
|
||||
|
||||
grpc_pollset_kick(pollset);
|
||||
}
|
||||
|
||||
static void unary_poll_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
static void basic_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
GPR_ASSERT(fd);
|
||||
if (fd == pollset->data.ptr) {
|
||||
grpc_fd_unref(pollset->data.ptr);
|
||||
become_empty_pollset(pollset);
|
||||
GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
|
||||
pollset->data.ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
|
||||
gpr_timespec deadline,
|
||||
gpr_timespec now,
|
||||
int allow_synchronous_callback) {
|
||||
static int basic_pollset_maybe_work(grpc_pollset *pollset,
|
||||
gpr_timespec deadline, gpr_timespec now,
|
||||
int allow_synchronous_callback) {
|
||||
struct pollfd pfd[2];
|
||||
grpc_fd *fd;
|
||||
grpc_fd_watcher fd_watcher;
|
||||
grpc_kick_fd_info *kfd;
|
||||
int timeout;
|
||||
int r;
|
||||
int nfds;
|
||||
|
||||
if (pollset->counter) {
|
||||
return 0;
|
||||
}
|
||||
if (pollset->in_flight_cbs) {
|
||||
/* Give do_promote priority so we don't starve it out */
|
||||
return 0;
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
return 1;
|
||||
}
|
||||
fd = pollset->data.ptr;
|
||||
if (grpc_fd_is_orphaned(fd)) {
|
||||
grpc_fd_unref(fd);
|
||||
become_empty_pollset(pollset);
|
||||
return 0;
|
||||
if (fd && grpc_fd_is_orphaned(fd)) {
|
||||
GRPC_FD_UNREF(fd, "basicpoll");
|
||||
fd = pollset->data.ptr = NULL;
|
||||
}
|
||||
if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
|
||||
timeout = -1;
|
||||
} else {
|
||||
timeout = gpr_time_to_millis(gpr_time_sub(deadline, now));
|
||||
if (timeout <= 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pfd[0].fd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
|
||||
if (pfd[0].fd < 0) {
|
||||
timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
|
||||
kfd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
|
||||
if (kfd == NULL) {
|
||||
/* Already kicked */
|
||||
return 1;
|
||||
}
|
||||
pfd[0].fd = GRPC_POLLSET_KICK_GET_FD(kfd);
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[0].revents = 0;
|
||||
pfd[1].fd = fd->fd;
|
||||
pfd[1].revents = 0;
|
||||
pollset->counter = 1;
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
|
||||
pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
|
||||
nfds = 1;
|
||||
pollset->counter++;
|
||||
if (fd) {
|
||||
pfd[1].fd = fd->fd;
|
||||
pfd[1].revents = 0;
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
pfd[1].events =
|
||||
grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
|
||||
if (pfd[1].events != 0) {
|
||||
nfds++;
|
||||
}
|
||||
} else {
|
||||
gpr_mu_unlock(&pollset->mu);
|
||||
}
|
||||
|
||||
/* poll fd count (argument 2) is shortened by one if we have no events
|
||||
to poll on - such that it only includes the kicker */
|
||||
r = poll(pfd, GPR_ARRAY_SIZE(pfd) - (pfd[1].events == 0), timeout);
|
||||
r = poll(pfd, nfds, timeout);
|
||||
GRPC_TIMER_MARK(GRPC_PTAG_POLL_FINISHED, r);
|
||||
|
||||
grpc_fd_end_poll(&fd_watcher, pfd[1].revents & POLLIN, pfd[1].revents & POLLOUT);
|
||||
if (fd) {
|
||||
grpc_fd_end_poll(&fd_watcher, pfd[1].revents & POLLIN,
|
||||
pfd[1].revents & POLLOUT);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
if (errno != EINTR) {
|
||||
|
|
@ -438,39 +402,44 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
|
|||
/* do nothing */
|
||||
} else {
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
grpc_pollset_kick_consume(&pollset->kick_state);
|
||||
grpc_pollset_kick_consume(&pollset->kick_state, kfd);
|
||||
}
|
||||
if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
|
||||
grpc_fd_become_readable(fd, allow_synchronous_callback);
|
||||
}
|
||||
if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) {
|
||||
grpc_fd_become_writable(fd, allow_synchronous_callback);
|
||||
if (nfds > 1) {
|
||||
if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
|
||||
grpc_fd_become_readable(fd, allow_synchronous_callback);
|
||||
}
|
||||
if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) {
|
||||
grpc_fd_become_writable(fd, allow_synchronous_callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grpc_pollset_kick_post_poll(&pollset->kick_state);
|
||||
grpc_pollset_kick_post_poll(&pollset->kick_state, kfd);
|
||||
|
||||
gpr_mu_lock(&pollset->mu);
|
||||
pollset->counter = 0;
|
||||
gpr_cv_broadcast(&pollset->cv);
|
||||
pollset->counter--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void unary_poll_pollset_destroy(grpc_pollset *pollset) {
|
||||
static void basic_pollset_destroy(grpc_pollset *pollset) {
|
||||
GPR_ASSERT(pollset->counter == 0);
|
||||
grpc_fd_unref(pollset->data.ptr);
|
||||
if (pollset->data.ptr != NULL) {
|
||||
GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
|
||||
pollset->data.ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const grpc_pollset_vtable unary_poll_pollset = {
|
||||
unary_poll_pollset_add_fd, unary_poll_pollset_del_fd,
|
||||
unary_poll_pollset_maybe_work, kick_using_pollset_kick,
|
||||
unary_poll_pollset_destroy};
|
||||
static const grpc_pollset_vtable basic_pollset = {
|
||||
basic_pollset_add_fd, basic_pollset_del_fd, basic_pollset_maybe_work,
|
||||
kick_using_pollset_kick, basic_pollset_destroy, basic_pollset_destroy};
|
||||
|
||||
static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd) {
|
||||
pollset->vtable = &unary_poll_pollset;
|
||||
static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
|
||||
pollset->vtable = &basic_pollset;
|
||||
pollset->counter = 0;
|
||||
pollset->data.ptr = fd;
|
||||
grpc_fd_ref(fd);
|
||||
pollset->data.ptr = fd_or_null;
|
||||
if (fd_or_null) {
|
||||
GRPC_FD_REF(fd_or_null, "basicpoll");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GPR_POSIX_POLLSET */
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#include <grpc/support/sync.h>
|
||||
|
||||
#include "src/core/iomgr/pollset_kick.h"
|
||||
#include "src/core/iomgr/pollset_kick_posix.h"
|
||||
|
||||
typedef struct grpc_pollset_vtable grpc_pollset_vtable;
|
||||
|
||||
|
|
@ -52,11 +52,11 @@ typedef struct grpc_pollset {
|
|||
few fds, and an epoll() based implementation for many fds */
|
||||
const grpc_pollset_vtable *vtable;
|
||||
gpr_mu mu;
|
||||
gpr_cv cv;
|
||||
grpc_pollset_kick_state kick_state;
|
||||
int counter;
|
||||
int in_flight_cbs;
|
||||
int shutting_down;
|
||||
int called_shutdown;
|
||||
void (*shutdown_done_cb)(void *arg);
|
||||
void *shutdown_done_arg;
|
||||
union {
|
||||
|
|
@ -71,11 +71,11 @@ struct grpc_pollset_vtable {
|
|||
int (*maybe_work)(grpc_pollset *pollset, gpr_timespec deadline,
|
||||
gpr_timespec now, int allow_synchronous_callback);
|
||||
void (*kick)(grpc_pollset *pollset);
|
||||
void (*finish_shutdown)(grpc_pollset *pollset);
|
||||
void (*destroy)(grpc_pollset *pollset);
|
||||
};
|
||||
|
||||
#define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)
|
||||
#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv)
|
||||
|
||||
/* Add an fd to a pollset */
|
||||
void grpc_pollset_add_fd(grpc_pollset *pollset, struct grpc_fd *fd);
|
||||
|
|
@ -94,11 +94,14 @@ int grpc_kick_read_fd(grpc_pollset *p);
|
|||
/* Call after polling has been kicked to leave the kicked state */
|
||||
void grpc_kick_drain(grpc_pollset *p);
|
||||
|
||||
/* All fds get added to a backup pollset to ensure that progress is made
|
||||
regardless of applications listening to events. Relying on this is slow
|
||||
however (the backup pollset only listens every 100ms or so) - so it's not
|
||||
to be relied on. */
|
||||
grpc_pollset *grpc_backup_pollset(void);
|
||||
/* Convert a timespec to milliseconds:
|
||||
- very small or negative poll times are clamped to zero to do a
|
||||
non-blocking poll (which becomes spin polling)
|
||||
- other small values are rounded up to one millisecond
|
||||
- longer than a millisecond polls are rounded up to the next nearest
|
||||
millisecond to avoid spinning
|
||||
- infinite timeouts are converted to -1 */
|
||||
int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now);
|
||||
|
||||
/* turn a pollset into a multipoller: platform specific */
|
||||
typedef void (*grpc_platform_become_multipoller_type)(grpc_pollset *pollset,
|
||||
|
|
|
|||
|
|
@ -31,44 +31,29 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_H
|
||||
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_H
|
||||
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H
|
||||
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
#include "src/core/iomgr/pollset.h"
|
||||
|
||||
/* A grpc_pollset_set is a set of pollsets that are interested in an
|
||||
action. Adding a pollset to a pollset_set automatically adds any
|
||||
fd's (etc) that have been registered with the set_set with that pollset.
|
||||
Registering fd's automatically adds them to all current pollsets. */
|
||||
|
||||
#ifdef GPR_POSIX_SOCKET
|
||||
#include "src/core/iomgr/pollset_kick_posix.h"
|
||||
#include "src/core/iomgr/pollset_set_posix.h"
|
||||
#endif
|
||||
|
||||
#ifdef GPR_WIN32
|
||||
#include "src/core/iomgr/pollset_kick_windows.h"
|
||||
#include "src/core/iomgr/pollset_set_windows.h"
|
||||
#endif
|
||||
|
||||
/* This is an abstraction around the typical pipe mechanism for waking up a
|
||||
thread sitting in a poll() style call. */
|
||||
void grpc_pollset_set_init(grpc_pollset_set *pollset_set);
|
||||
void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set);
|
||||
void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
|
||||
grpc_pollset *pollset);
|
||||
void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set,
|
||||
grpc_pollset *pollset);
|
||||
|
||||
void grpc_pollset_kick_global_init(void);
|
||||
void grpc_pollset_kick_global_destroy(void);
|
||||
|
||||
void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state);
|
||||
void grpc_pollset_kick_destroy(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
/* Guarantees a pure posix implementation rather than a specialized one, if
|
||||
* applicable. Intended for testing. */
|
||||
void grpc_pollset_kick_global_init_fallback_fd(void);
|
||||
|
||||
/* Must be called before entering poll(). If return value is -1, this consumed
|
||||
an existing kick. Otherwise the return value is an FD to add to the poll set.
|
||||
*/
|
||||
int grpc_pollset_kick_pre_poll(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
/* Consume an existing kick. Must be called after poll returns that the fd was
|
||||
readable, and before calling kick_post_poll. */
|
||||
void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
/* Must be called after pre_poll, and after consume if applicable */
|
||||
void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#ifdef GPR_POSIX_SOCKET
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/useful.h>
|
||||
|
||||
#include "src/core/iomgr/pollset_set.h"
|
||||
|
||||
void grpc_pollset_set_init(grpc_pollset_set *pollset_set) {
|
||||
memset(pollset_set, 0, sizeof(*pollset_set));
|
||||
gpr_mu_init(&pollset_set->mu);
|
||||
}
|
||||
|
||||
void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
|
||||
size_t i;
|
||||
gpr_mu_destroy(&pollset_set->mu);
|
||||
for (i = 0; i < pollset_set->fd_count; i++) {
|
||||
GRPC_FD_UNREF(pollset_set->fds[i], "pollset");
|
||||
}
|
||||
gpr_free(pollset_set->pollsets);
|
||||
gpr_free(pollset_set->fds);
|
||||
}
|
||||
|
||||
void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
|
||||
grpc_pollset *pollset) {
|
||||
size_t i;
|
||||
gpr_mu_lock(&pollset_set->mu);
|
||||
if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
|
||||
pollset_set->pollset_capacity =
|
||||
GPR_MAX(8, 2 * pollset_set->pollset_capacity);
|
||||
pollset_set->pollsets =
|
||||
gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity *
|
||||
sizeof(*pollset_set->pollsets));
|
||||
}
|
||||
pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
|
||||
for (i = 0; i < pollset_set->fd_count; i++) {
|
||||
grpc_pollset_add_fd(pollset, pollset_set->fds[i]);
|
||||
}
|
||||
gpr_mu_unlock(&pollset_set->mu);
|
||||
}
|
||||
|
||||
void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set,
|
||||
grpc_pollset *pollset) {
|
||||
size_t i;
|
||||
gpr_mu_lock(&pollset_set->mu);
|
||||
for (i = 0; i < pollset_set->pollset_count; i++) {
|
||||
if (pollset_set->pollsets[i] == pollset) {
|
||||
pollset_set->pollset_count--;
|
||||
GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i],
|
||||
pollset_set->pollsets[pollset_set->pollset_count]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gpr_mu_unlock(&pollset_set->mu);
|
||||
}
|
||||
|
||||
void grpc_pollset_set_add_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) {
|
||||
size_t i;
|
||||
gpr_mu_lock(&pollset_set->mu);
|
||||
if (pollset_set->fd_count == pollset_set->fd_capacity) {
|
||||
pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity);
|
||||
pollset_set->fds = gpr_realloc(
|
||||
pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds));
|
||||
}
|
||||
GRPC_FD_REF(fd, "pollset_set");
|
||||
pollset_set->fds[pollset_set->fd_count++] = fd;
|
||||
for (i = 0; i < pollset_set->pollset_count; i++) {
|
||||
grpc_pollset_add_fd(pollset_set->pollsets[i], fd);
|
||||
}
|
||||
gpr_mu_unlock(&pollset_set->mu);
|
||||
}
|
||||
|
||||
void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) {
|
||||
size_t i;
|
||||
gpr_mu_lock(&pollset_set->mu);
|
||||
for (i = 0; i < pollset_set->fd_count; i++) {
|
||||
if (pollset_set->fds[i] == fd) {
|
||||
pollset_set->fd_count--;
|
||||
GPR_SWAP(grpc_fd *, pollset_set->fds[i],
|
||||
pollset_set->fds[pollset_set->pollset_count]);
|
||||
GRPC_FD_UNREF(fd, "pollset_set");
|
||||
break;
|
||||
}
|
||||
}
|
||||
gpr_mu_unlock(&pollset_set->mu);
|
||||
}
|
||||
|
||||
#endif /* GPR_POSIX_SOCKET */
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
|
||||
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
|
||||
|
||||
#include "src/core/iomgr/fd_posix.h"
|
||||
#include "src/core/iomgr/pollset_posix.h"
|
||||
|
||||
typedef struct grpc_pollset_set {
|
||||
gpr_mu mu;
|
||||
|
||||
size_t pollset_count;
|
||||
size_t pollset_capacity;
|
||||
grpc_pollset **pollsets;
|
||||
|
||||
size_t fd_count;
|
||||
size_t fd_capacity;
|
||||
grpc_fd **fds;
|
||||
} grpc_pollset_set;
|
||||
|
||||
void grpc_pollset_set_add_fd(grpc_pollset_set *pollset_set, grpc_fd *fd);
|
||||
void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#ifdef GPR_WINSOCK_SOCKET
|
||||
|
||||
#include "src/core/iomgr/pollset_set.h"
|
||||
|
||||
void grpc_pollset_set_init(grpc_pollset_set *pollset_set) {}
|
||||
|
||||
void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {}
|
||||
|
||||
void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
|
||||
grpc_pollset *pollset) {}
|
||||
|
||||
void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set,
|
||||
grpc_pollset *pollset) {}
|
||||
|
||||
#endif /* GPR_WINSOCK_SOCKET */
|
||||
|
|
@ -31,18 +31,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_WINDOWS_H
|
||||
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_WINDOWS_H
|
||||
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
|
||||
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
|
||||
|
||||
#include <grpc/support/sync.h>
|
||||
typedef struct grpc_pollset_set { void *unused; } grpc_pollset_set;
|
||||
|
||||
/* There isn't really any such thing as a pollset under Windows, due to the
|
||||
nature of the IO completion ports. */
|
||||
|
||||
struct grpc_kick_fd_info;
|
||||
|
||||
typedef struct grpc_pollset_kick_state {
|
||||
int unused;
|
||||
} grpc_pollset_kick_state;
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_WINDOWS_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
|
||||
|
|
@ -46,10 +46,7 @@
|
|||
set of features for the sake of the rest of grpc. But grpc_pollset_work
|
||||
won't actually do any polling, and return as quickly as possible. */
|
||||
|
||||
void grpc_pollset_init(grpc_pollset *pollset) {
|
||||
gpr_mu_init(&pollset->mu);
|
||||
gpr_cv_init(&pollset->cv);
|
||||
}
|
||||
void grpc_pollset_init(grpc_pollset *pollset) { gpr_mu_init(&pollset->mu); }
|
||||
|
||||
void grpc_pollset_shutdown(grpc_pollset *pollset,
|
||||
void (*shutdown_done)(void *arg),
|
||||
|
|
@ -59,7 +56,6 @@ void grpc_pollset_shutdown(grpc_pollset *pollset,
|
|||
|
||||
void grpc_pollset_destroy(grpc_pollset *pollset) {
|
||||
gpr_mu_destroy(&pollset->mu);
|
||||
gpr_cv_destroy(&pollset->cv);
|
||||
}
|
||||
|
||||
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
|
||||
|
|
@ -77,6 +73,6 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
|
|||
return 0 /* GPR_FALSE */;
|
||||
}
|
||||
|
||||
void grpc_pollset_kick(grpc_pollset *p) { }
|
||||
void grpc_pollset_kick(grpc_pollset *p) {}
|
||||
|
||||
#endif /* GPR_WINSOCK_SOCKET */
|
||||
#endif /* GPR_WINSOCK_SOCKET */
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
#include <windows.h>
|
||||
#include <grpc/support/sync.h>
|
||||
|
||||
#include "src/core/iomgr/pollset_kick.h"
|
||||
#include "src/core/iomgr/socket_windows.h"
|
||||
|
||||
/* There isn't really any such thing as a pollset under Windows, due to the
|
||||
|
|
@ -45,12 +44,8 @@
|
|||
and a condition variable, as this is the minimal set of features we need
|
||||
implemented for the rest of grpc. But we won't use them directly. */
|
||||
|
||||
typedef struct grpc_pollset {
|
||||
gpr_mu mu;
|
||||
gpr_cv cv;
|
||||
} grpc_pollset;
|
||||
typedef struct grpc_pollset { gpr_mu mu; } grpc_pollset;
|
||||
|
||||
#define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)
|
||||
#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv)
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
|
||||
|
|
|
|||
|
|
@ -35,14 +35,18 @@
|
|||
#define GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H
|
||||
|
||||
#include "src/core/iomgr/endpoint.h"
|
||||
#include "src/core/iomgr/pollset_set.h"
|
||||
#include "src/core/iomgr/sockaddr.h"
|
||||
#include <grpc/support/time.h>
|
||||
|
||||
/* Asynchronously connect to an address (specified as (addr, len)), and call
|
||||
cb with arg and the completed connection when done (or call cb with arg and
|
||||
NULL on failure) */
|
||||
NULL on failure).
|
||||
interested_parties points to a set of pollsets that would be interested
|
||||
in this connection being established (in order to continue their work) */
|
||||
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
|
||||
void *arg, const struct sockaddr *addr,
|
||||
int addr_len, gpr_timespec deadline);
|
||||
void *arg, grpc_pollset_set *interested_parties,
|
||||
const struct sockaddr *addr, int addr_len,
|
||||
gpr_timespec deadline);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H */
|
||||
|
|
|
|||
|
|
@ -113,8 +113,6 @@ static void on_writable(void *acp, int success) {
|
|||
void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
|
||||
void *cb_arg = ac->cb_arg;
|
||||
|
||||
grpc_alarm_cancel(&ac->alarm);
|
||||
|
||||
if (success) {
|
||||
do {
|
||||
so_error_size = sizeof(so_error);
|
||||
|
|
@ -167,26 +165,30 @@ static void on_writable(void *acp, int success) {
|
|||
finish:
|
||||
gpr_mu_lock(&ac->mu);
|
||||
if (!ep) {
|
||||
grpc_fd_orphan(ac->fd, NULL, NULL);
|
||||
grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
|
||||
}
|
||||
done = (--ac->refs == 0);
|
||||
gpr_mu_unlock(&ac->mu);
|
||||
if (done) {
|
||||
gpr_mu_destroy(&ac->mu);
|
||||
gpr_free(ac);
|
||||
} else {
|
||||
grpc_alarm_cancel(&ac->alarm);
|
||||
}
|
||||
cb(cb_arg, ep);
|
||||
}
|
||||
|
||||
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
|
||||
void *arg, const struct sockaddr *addr,
|
||||
int addr_len, gpr_timespec deadline) {
|
||||
void *arg, grpc_pollset_set *interested_parties,
|
||||
const struct sockaddr *addr, int addr_len,
|
||||
gpr_timespec deadline) {
|
||||
int fd;
|
||||
grpc_dualstack_mode dsmode;
|
||||
int err;
|
||||
async_connect *ac;
|
||||
struct sockaddr_in6 addr6_v4mapped;
|
||||
struct sockaddr_in addr4_copy;
|
||||
grpc_fd *fdobj;
|
||||
char *name;
|
||||
char *addr_str;
|
||||
|
||||
|
|
@ -218,31 +220,35 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
|
|||
grpc_sockaddr_to_string(&addr_str, addr, 1);
|
||||
gpr_asprintf(&name, "tcp-client:%s", addr_str);
|
||||
|
||||
fdobj = grpc_fd_create(fd, name);
|
||||
|
||||
if (err >= 0) {
|
||||
gpr_log(GPR_DEBUG, "instant connect");
|
||||
cb(arg, grpc_tcp_create(grpc_fd_create(fd, name),
|
||||
GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
|
||||
cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
|
||||
gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
|
||||
close(fd);
|
||||
grpc_fd_orphan(fdobj, NULL, "tcp_client_connect_error");
|
||||
cb(arg, NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
grpc_pollset_set_add_fd(interested_parties, fdobj);
|
||||
|
||||
ac = gpr_malloc(sizeof(async_connect));
|
||||
ac->cb = cb;
|
||||
ac->cb_arg = arg;
|
||||
ac->fd = grpc_fd_create(fd, name);
|
||||
ac->fd = fdobj;
|
||||
gpr_mu_init(&ac->mu);
|
||||
ac->refs = 2;
|
||||
ac->write_closure.cb = on_writable;
|
||||
ac->write_closure.cb_arg = ac;
|
||||
|
||||
gpr_mu_lock(&ac->mu);
|
||||
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
|
||||
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
|
||||
gpr_mu_unlock(&ac->mu);
|
||||
|
||||
done:
|
||||
gpr_free(name);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
#include "src/core/iomgr/socket_windows.h"
|
||||
|
||||
typedef struct {
|
||||
void(*cb)(void *arg, grpc_endpoint *tcp);
|
||||
void (*cb)(void *arg, grpc_endpoint *tcp);
|
||||
void *cb_arg;
|
||||
gpr_mu mu;
|
||||
grpc_winsocket *socket;
|
||||
|
|
@ -86,7 +86,7 @@ static void on_connect(void *acp, int from_iocp) {
|
|||
SOCKET sock = ac->socket->socket;
|
||||
grpc_endpoint *ep = NULL;
|
||||
grpc_winsocket_callback_info *info = &ac->socket->write_info;
|
||||
void(*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
|
||||
void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
|
||||
void *cb_arg = ac->cb_arg;
|
||||
int aborted;
|
||||
|
||||
|
|
@ -99,8 +99,7 @@ static void on_connect(void *acp, int from_iocp) {
|
|||
DWORD transfered_bytes = 0;
|
||||
DWORD flags;
|
||||
BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
|
||||
&transfered_bytes, FALSE,
|
||||
&flags);
|
||||
&transfered_bytes, FALSE, &flags);
|
||||
info->outstanding = 0;
|
||||
GPR_ASSERT(transfered_bytes == 0);
|
||||
if (!wsa_success) {
|
||||
|
|
@ -138,9 +137,10 @@ static void on_connect(void *acp, int from_iocp) {
|
|||
|
||||
/* Tries to issue one async connection, then schedules both an IOCP
|
||||
notification request for the connection, and one timeout alert. */
|
||||
void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
|
||||
void *arg, const struct sockaddr *addr,
|
||||
int addr_len, gpr_timespec deadline) {
|
||||
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
|
||||
void *arg, grpc_pollset_set *interested_parties,
|
||||
const struct sockaddr *addr, int addr_len,
|
||||
gpr_timespec deadline) {
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
BOOL success;
|
||||
int status;
|
||||
|
|
@ -175,9 +175,9 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
|
|||
|
||||
/* Grab the function pointer for ConnectEx for that specific socket.
|
||||
It may change depending on the interface. */
|
||||
status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||
&guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx),
|
||||
&ioctl_num_bytes, NULL, NULL);
|
||||
status =
|
||||
WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
|
||||
&ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);
|
||||
|
||||
if (status != 0) {
|
||||
message = "Unable to retrieve ConnectEx pointer: %s";
|
||||
|
|
@ -186,8 +186,7 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
|
|||
|
||||
grpc_sockaddr_make_wildcard6(0, &local_address);
|
||||
|
||||
status = bind(sock, (struct sockaddr *) &local_address,
|
||||
sizeof(local_address));
|
||||
status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
|
||||
if (status != 0) {
|
||||
message = "Unable to bind socket: %s";
|
||||
goto failure;
|
||||
|
|
@ -233,4 +232,4 @@ failure:
|
|||
cb(arg, NULL);
|
||||
}
|
||||
|
||||
#endif /* GPR_WINSOCK_SOCKET */
|
||||
#endif /* GPR_WINSOCK_SOCKET */
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ typedef struct {
|
|||
grpc_endpoint base;
|
||||
grpc_fd *em_fd;
|
||||
int fd;
|
||||
int iov_size; /* Number of slices to allocate per read attempt */
|
||||
int iov_size; /* Number of slices to allocate per read attempt */
|
||||
int finished_edge;
|
||||
size_t slice_size;
|
||||
gpr_refcount refcount;
|
||||
|
|
@ -295,7 +295,7 @@ static void grpc_tcp_shutdown(grpc_endpoint *ep) {
|
|||
static void grpc_tcp_unref(grpc_tcp *tcp) {
|
||||
int refcount_zero = gpr_unref(&tcp->refcount);
|
||||
if (refcount_zero) {
|
||||
grpc_fd_orphan(tcp->em_fd, NULL, NULL);
|
||||
grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan");
|
||||
gpr_free(tcp);
|
||||
}
|
||||
}
|
||||
|
|
@ -412,8 +412,7 @@ static void grpc_tcp_continue_read(grpc_tcp *tcp) {
|
|||
++tcp->iov_size;
|
||||
}
|
||||
GPR_ASSERT(slice_state_has_available(&read_state));
|
||||
slice_state_transfer_ownership(&read_state, &final_slices,
|
||||
&final_nslices);
|
||||
slice_state_transfer_ownership(&read_state, &final_slices, &final_nslices);
|
||||
call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK);
|
||||
slice_state_destroy(&read_state);
|
||||
grpc_tcp_unref(tcp);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ typedef struct {
|
|||
} addr;
|
||||
int addr_len;
|
||||
grpc_iomgr_closure read_closure;
|
||||
grpc_iomgr_closure destroyed_closure;
|
||||
} server_port;
|
||||
|
||||
static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
|
||||
|
|
@ -101,13 +102,15 @@ struct grpc_tcp_server {
|
|||
void *cb_arg;
|
||||
|
||||
gpr_mu mu;
|
||||
gpr_cv cv;
|
||||
|
||||
/* active port count: how many ports are actually still listening */
|
||||
size_t active_ports;
|
||||
/* destroyed port count: how many ports are completely destroyed */
|
||||
size_t destroyed_ports;
|
||||
|
||||
/* is this server shutting down? (boolean) */
|
||||
int shutdown;
|
||||
|
||||
/* all listening ports */
|
||||
server_port *ports;
|
||||
size_t nports;
|
||||
|
|
@ -116,14 +119,19 @@ struct grpc_tcp_server {
|
|||
/* shutdown callback */
|
||||
void (*shutdown_complete)(void *);
|
||||
void *shutdown_complete_arg;
|
||||
|
||||
/* all pollsets interested in new connections */
|
||||
grpc_pollset **pollsets;
|
||||
/* number of pollsets in the pollsets array */
|
||||
size_t pollset_count;
|
||||
};
|
||||
|
||||
grpc_tcp_server *grpc_tcp_server_create(void) {
|
||||
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
|
||||
gpr_mu_init(&s->mu);
|
||||
gpr_cv_init(&s->cv);
|
||||
s->active_ports = 0;
|
||||
s->destroyed_ports = 0;
|
||||
s->shutdown = 0;
|
||||
s->cb = NULL;
|
||||
s->cb_arg = NULL;
|
||||
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
|
||||
|
|
@ -136,7 +144,6 @@ static void finish_shutdown(grpc_tcp_server *s) {
|
|||
s->shutdown_complete(s->shutdown_complete_arg);
|
||||
|
||||
gpr_mu_destroy(&s->mu);
|
||||
gpr_cv_destroy(&s->cv);
|
||||
|
||||
gpr_free(s->ports);
|
||||
gpr_free(s);
|
||||
|
|
@ -156,40 +163,60 @@ static void destroyed_port(void *server, int success) {
|
|||
|
||||
static void dont_care_about_shutdown_completion(void *ignored) {}
|
||||
|
||||
/* called when all listening endpoints have been shutdown, so no further
|
||||
events will be received on them - at this point it's safe to destroy
|
||||
things */
|
||||
static void deactivated_all_ports(grpc_tcp_server *s) {
|
||||
size_t i;
|
||||
|
||||
/* delete ALL the things */
|
||||
gpr_mu_lock(&s->mu);
|
||||
|
||||
if (!s->shutdown) {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->nports) {
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
server_port *sp = &s->ports[i];
|
||||
if (sp->addr.sockaddr.sa_family == AF_UNIX) {
|
||||
unlink_if_unix_domain_socket(&sp->addr.un);
|
||||
}
|
||||
sp->destroyed_closure.cb = destroyed_port;
|
||||
sp->destroyed_closure.cb_arg = s;
|
||||
grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, "tcp_listener_shutdown");
|
||||
}
|
||||
gpr_mu_unlock(&s->mu);
|
||||
} else {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
finish_shutdown(s);
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_tcp_server_destroy(
|
||||
grpc_tcp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg),
|
||||
void *shutdown_complete_arg) {
|
||||
size_t i;
|
||||
gpr_mu_lock(&s->mu);
|
||||
|
||||
GPR_ASSERT(!s->shutdown);
|
||||
s->shutdown = 1;
|
||||
|
||||
s->shutdown_complete = shutdown_complete
|
||||
? shutdown_complete
|
||||
: dont_care_about_shutdown_completion;
|
||||
s->shutdown_complete_arg = shutdown_complete_arg;
|
||||
|
||||
/* shutdown all fd's */
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
grpc_fd_shutdown(s->ports[i].emfd);
|
||||
}
|
||||
/* wait while that happens */
|
||||
/* TODO(ctiller): make this asynchronous also */
|
||||
while (s->active_ports) {
|
||||
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
|
||||
}
|
||||
|
||||
/* delete ALL the things */
|
||||
if (s->nports) {
|
||||
if (s->active_ports) {
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
server_port *sp = &s->ports[i];
|
||||
if (sp->addr.sockaddr.sa_family == AF_UNIX) {
|
||||
unlink_if_unix_domain_socket(&sp->addr.un);
|
||||
}
|
||||
grpc_fd_orphan(sp->emfd, destroyed_port, s);
|
||||
grpc_fd_shutdown(s->ports[i].emfd);
|
||||
}
|
||||
gpr_mu_unlock(&s->mu);
|
||||
} else {
|
||||
gpr_mu_unlock(&s->mu);
|
||||
finish_shutdown(s);
|
||||
deactivated_all_ports(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,6 +301,8 @@ error:
|
|||
/* event manager callback when reads are ready */
|
||||
static void on_read(void *arg, int success) {
|
||||
server_port *sp = arg;
|
||||
grpc_fd *fdobj;
|
||||
size_t i;
|
||||
|
||||
if (!success) {
|
||||
goto error;
|
||||
|
|
@ -306,12 +335,18 @@ static void on_read(void *arg, int success) {
|
|||
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
|
||||
gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
|
||||
|
||||
fdobj = grpc_fd_create(fd, name);
|
||||
/* TODO(ctiller): revise this when we have server-side sharding
|
||||
of channels -- we certainly should not be automatically adding every
|
||||
incoming channel to every pollset owned by the server */
|
||||
for (i = 0; i < sp->server->pollset_count; i++) {
|
||||
grpc_pollset_add_fd(sp->server->pollsets[i], fdobj);
|
||||
}
|
||||
sp->server->cb(sp->server->cb_arg,
|
||||
grpc_tcp_create(grpc_fd_create(fd, name),
|
||||
GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
|
||||
grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
|
||||
|
||||
gpr_free(addr_str);
|
||||
gpr_free(name);
|
||||
gpr_free(addr_str);
|
||||
}
|
||||
|
||||
abort();
|
||||
|
|
@ -319,9 +354,11 @@ static void on_read(void *arg, int success) {
|
|||
error:
|
||||
gpr_mu_lock(&sp->server->mu);
|
||||
if (0 == --sp->server->active_ports) {
|
||||
gpr_cv_broadcast(&sp->server->cv);
|
||||
gpr_mu_unlock(&sp->server->mu);
|
||||
deactivated_all_ports(sp->server);
|
||||
} else {
|
||||
gpr_mu_unlock(&sp->server->mu);
|
||||
}
|
||||
gpr_mu_unlock(&sp->server->mu);
|
||||
}
|
||||
|
||||
static int add_socket_to_server(grpc_tcp_server *s, int fd,
|
||||
|
|
@ -452,6 +489,8 @@ void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollsets,
|
|||
GPR_ASSERT(s->active_ports == 0);
|
||||
s->cb = cb;
|
||||
s->cb_arg = cb_arg;
|
||||
s->pollsets = pollsets;
|
||||
s->pollset_count = pollset_count;
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
for (j = 0; j < pollset_count; j++) {
|
||||
grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd);
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ static void on_read(void *tcpp, int from_iocp) {
|
|||
status = GRPC_ENDPOINT_CB_ERROR;
|
||||
} else {
|
||||
if (info->bytes_transfered != 0) {
|
||||
sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
|
||||
sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
|
||||
status = GRPC_ENDPOINT_CB_OK;
|
||||
slice = ⊂
|
||||
nslices = 1;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ typedef struct grpc_json {
|
|||
* strings in the tree. The input stream's UTF-8 isn't validated,
|
||||
* as in, what you input is what you get as an output.
|
||||
*
|
||||
* All the keys and values in the grpc_json_t objects will be strings
|
||||
* All the keys and values in the grpc_json objects will be strings
|
||||
* pointing at your input buffer.
|
||||
*
|
||||
* Delete the allocated tree afterward using grpc_json_destroy().
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ typedef struct {
|
|||
grpc_credentials *creds;
|
||||
grpc_mdstr *host;
|
||||
grpc_mdstr *method;
|
||||
/* pollset bound to this call; if we need to make external
|
||||
network requests, they should be done under this pollset
|
||||
so that work can progress when this call wants work to
|
||||
progress */
|
||||
grpc_pollset *pollset;
|
||||
grpc_transport_op op;
|
||||
size_t op_md_idx;
|
||||
int sent_initial_metadata;
|
||||
|
|
@ -161,8 +166,9 @@ static void send_security_metadata(grpc_call_element *elem,
|
|||
service_url =
|
||||
build_service_url(chand->security_connector->base.url_scheme, calld);
|
||||
calld->op = *op; /* Copy op (originates from the caller's stack). */
|
||||
grpc_credentials_get_request_metadata(calld->creds, service_url,
|
||||
on_credentials_metadata, elem);
|
||||
GPR_ASSERT(calld->pollset);
|
||||
grpc_credentials_get_request_metadata(
|
||||
calld->creds, calld->pollset, service_url, on_credentials_metadata, elem);
|
||||
gpr_free(service_url);
|
||||
}
|
||||
|
||||
|
|
@ -196,6 +202,10 @@ static void auth_start_transport_op(grpc_call_element *elem,
|
|||
|
||||
/* TODO(jboeuf): write the call auth context. */
|
||||
|
||||
if (op->bind_pollset) {
|
||||
calld->pollset = op->bind_pollset;
|
||||
}
|
||||
|
||||
if (op->send_ops && !calld->sent_initial_metadata) {
|
||||
size_t nops = op->send_ops->nops;
|
||||
grpc_stream_op *ops = op->send_ops->ops;
|
||||
|
|
@ -258,6 +268,7 @@ static void init_call_elem(grpc_call_element *elem,
|
|||
calld->creds = NULL;
|
||||
calld->host = NULL;
|
||||
calld->method = NULL;
|
||||
calld->pollset = NULL;
|
||||
calld->sent_initial_metadata = 0;
|
||||
|
||||
GPR_ASSERT(!initial_op || !initial_op->send_ops);
|
||||
|
|
@ -296,13 +307,10 @@ static void init_channel_elem(grpc_channel_element *elem,
|
|||
chand->security_connector =
|
||||
(grpc_channel_security_connector *)grpc_security_connector_ref(sc);
|
||||
chand->md_ctx = metadata_context;
|
||||
chand->authority_string =
|
||||
grpc_mdstr_from_string(chand->md_ctx, ":authority");
|
||||
chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
|
||||
chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
|
||||
chand->error_msg_key =
|
||||
grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
|
||||
chand->status_key =
|
||||
grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
|
||||
chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
|
||||
chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
|
||||
}
|
||||
|
||||
/* Destructor for channel data */
|
||||
|
|
@ -326,6 +334,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
|
|||
}
|
||||
|
||||
const grpc_channel_filter grpc_client_auth_filter = {
|
||||
auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
|
||||
destroy_call_elem, sizeof(channel_data), init_channel_elem,
|
||||
destroy_channel_elem, "client-auth"};
|
||||
auth_start_transport_op, channel_op, sizeof(call_data),
|
||||
init_call_elem, destroy_call_elem, sizeof(channel_data),
|
||||
init_channel_elem, destroy_channel_elem, "client-auth"};
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
|
|||
}
|
||||
|
||||
void grpc_credentials_get_request_metadata(grpc_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
|
|
@ -116,7 +117,8 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds,
|
|||
}
|
||||
return;
|
||||
}
|
||||
creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
|
||||
creds->vtable->get_request_metadata(creds, pollset, service_url, cb,
|
||||
user_data);
|
||||
}
|
||||
|
||||
grpc_security_status grpc_credentials_create_security_connector(
|
||||
|
|
@ -191,9 +193,7 @@ static void ssl_server_destroy(grpc_server_credentials *creds) {
|
|||
gpr_free(creds);
|
||||
}
|
||||
|
||||
static int ssl_has_request_metadata(const grpc_credentials *creds) {
|
||||
return 0;
|
||||
}
|
||||
static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
|
||||
|
||||
static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
|
||||
return 0;
|
||||
|
|
@ -368,8 +368,8 @@ static int jwt_has_request_metadata_only(const grpc_credentials *creds) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void jwt_get_request_metadata(grpc_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
|
|
@ -450,6 +450,8 @@ grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
|
|||
from an http service. */
|
||||
|
||||
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
|
||||
grpc_httpcli_context *http_context,
|
||||
grpc_pollset *pollset,
|
||||
grpc_httpcli_response_cb response_cb,
|
||||
gpr_timespec deadline);
|
||||
|
||||
|
|
@ -458,6 +460,8 @@ typedef struct {
|
|||
gpr_mu mu;
|
||||
grpc_credentials_md_store *access_token_md;
|
||||
gpr_timespec token_expiration;
|
||||
grpc_httpcli_context httpcli_context;
|
||||
grpc_pollset_set pollset_set;
|
||||
grpc_fetch_oauth2_func fetch_func;
|
||||
} grpc_oauth2_token_fetcher_credentials;
|
||||
|
||||
|
|
@ -466,6 +470,7 @@ static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
|
|||
(grpc_oauth2_token_fetcher_credentials *)creds;
|
||||
grpc_credentials_md_store_unref(c->access_token_md);
|
||||
gpr_mu_destroy(&c->mu);
|
||||
grpc_httpcli_context_destroy(&c->httpcli_context);
|
||||
gpr_free(c);
|
||||
}
|
||||
|
||||
|
|
@ -481,8 +486,8 @@ static int oauth2_token_fetcher_has_request_metadata_only(
|
|||
|
||||
grpc_credentials_status
|
||||
grpc_oauth2_token_fetcher_credentials_parse_server_response(
|
||||
const grpc_httpcli_response *response,
|
||||
grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) {
|
||||
const grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
|
||||
gpr_timespec *token_lifetime) {
|
||||
char *null_terminated_body = NULL;
|
||||
char *new_access_token = NULL;
|
||||
grpc_credentials_status status = GRPC_CREDENTIALS_OK;
|
||||
|
|
@ -593,7 +598,7 @@ static void on_oauth2_token_fetcher_http_response(
|
|||
}
|
||||
|
||||
static void oauth2_token_fetcher_get_request_metadata(
|
||||
grpc_credentials *creds, const char *service_url,
|
||||
grpc_credentials *creds, grpc_pollset *pollset, const char *service_url,
|
||||
grpc_credentials_metadata_cb cb, void *user_data) {
|
||||
grpc_oauth2_token_fetcher_credentials *c =
|
||||
(grpc_oauth2_token_fetcher_credentials *)creds;
|
||||
|
|
@ -605,7 +610,8 @@ static void oauth2_token_fetcher_get_request_metadata(
|
|||
if (c->access_token_md != NULL &&
|
||||
(gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
|
||||
refresh_threshold) > 0)) {
|
||||
cached_access_token_md = grpc_credentials_md_store_ref(c->access_token_md);
|
||||
cached_access_token_md =
|
||||
grpc_credentials_md_store_ref(c->access_token_md);
|
||||
}
|
||||
gpr_mu_unlock(&c->mu);
|
||||
}
|
||||
|
|
@ -616,7 +622,7 @@ static void oauth2_token_fetcher_get_request_metadata(
|
|||
} else {
|
||||
c->fetch_func(
|
||||
grpc_credentials_metadata_request_create(creds, cb, user_data),
|
||||
on_oauth2_token_fetcher_http_response,
|
||||
&c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
|
||||
gpr_time_add(gpr_now(), refresh_threshold));
|
||||
}
|
||||
}
|
||||
|
|
@ -629,6 +635,7 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
|
|||
gpr_mu_init(&c->mu);
|
||||
c->token_expiration = gpr_inf_past;
|
||||
c->fetch_func = fetch_func;
|
||||
grpc_pollset_set_init(&c->pollset_set);
|
||||
}
|
||||
|
||||
/* -- ComputeEngine credentials. -- */
|
||||
|
|
@ -640,6 +647,7 @@ static grpc_credentials_vtable compute_engine_vtable = {
|
|||
|
||||
static void compute_engine_fetch_oauth2(
|
||||
grpc_credentials_metadata_request *metadata_req,
|
||||
grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
|
||||
grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
|
||||
grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
|
||||
grpc_httpcli_request request;
|
||||
|
|
@ -648,7 +656,8 @@ static void compute_engine_fetch_oauth2(
|
|||
request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
|
||||
request.hdr_count = 1;
|
||||
request.hdrs = &header;
|
||||
grpc_httpcli_get(&request, deadline, response_cb, metadata_req);
|
||||
grpc_httpcli_get(httpcli_context, pollset, &request, deadline, response_cb,
|
||||
metadata_req);
|
||||
}
|
||||
|
||||
grpc_credentials *grpc_compute_engine_credentials_create(void) {
|
||||
|
|
@ -683,6 +692,7 @@ static grpc_credentials_vtable service_account_vtable = {
|
|||
|
||||
static void service_account_fetch_oauth2(
|
||||
grpc_credentials_metadata_request *metadata_req,
|
||||
grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
|
||||
grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
|
||||
grpc_service_account_credentials *c =
|
||||
(grpc_service_account_credentials *)metadata_req->creds;
|
||||
|
|
@ -708,8 +718,8 @@ static void service_account_fetch_oauth2(
|
|||
request.hdr_count = 1;
|
||||
request.hdrs = &header;
|
||||
request.use_ssl = 1;
|
||||
grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
|
||||
metadata_req);
|
||||
grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
|
||||
deadline, response_cb, metadata_req);
|
||||
gpr_free(body);
|
||||
gpr_free(jwt);
|
||||
}
|
||||
|
|
@ -743,8 +753,7 @@ typedef struct {
|
|||
} grpc_refresh_token_credentials;
|
||||
|
||||
static void refresh_token_destroy(grpc_credentials *creds) {
|
||||
grpc_refresh_token_credentials *c =
|
||||
(grpc_refresh_token_credentials *)creds;
|
||||
grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
|
||||
grpc_auth_refresh_token_destruct(&c->refresh_token);
|
||||
oauth2_token_fetcher_destroy(&c->base.base);
|
||||
}
|
||||
|
|
@ -756,6 +765,7 @@ static grpc_credentials_vtable refresh_token_vtable = {
|
|||
|
||||
static void refresh_token_fetch_oauth2(
|
||||
grpc_credentials_metadata_request *metadata_req,
|
||||
grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
|
||||
grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
|
||||
grpc_refresh_token_credentials *c =
|
||||
(grpc_refresh_token_credentials *)metadata_req->creds;
|
||||
|
|
@ -772,8 +782,8 @@ static void refresh_token_fetch_oauth2(
|
|||
request.hdr_count = 1;
|
||||
request.hdrs = &header;
|
||||
request.use_ssl = 1;
|
||||
grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
|
||||
metadata_req);
|
||||
grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
|
||||
deadline, response_cb, metadata_req);
|
||||
gpr_free(body);
|
||||
}
|
||||
|
||||
|
|
@ -784,8 +794,7 @@ grpc_credentials *grpc_refresh_token_credentials_create(
|
|||
grpc_auth_refresh_token_create_from_string(json_refresh_token);
|
||||
|
||||
if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Invalid input for refresh token credentials creation");
|
||||
gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
|
||||
return NULL;
|
||||
}
|
||||
c = gpr_malloc(sizeof(grpc_refresh_token_credentials));
|
||||
|
|
@ -830,6 +839,7 @@ void on_simulated_token_fetch_done(void *user_data, int success) {
|
|||
}
|
||||
|
||||
static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
|
|
@ -888,8 +898,7 @@ static int fake_transport_security_has_request_metadata_only(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static grpc_security_status
|
||||
fake_transport_security_create_security_connector(
|
||||
static grpc_security_status fake_transport_security_create_security_connector(
|
||||
grpc_credentials *c, const char *target, const grpc_channel_args *args,
|
||||
grpc_credentials *request_metadata_creds,
|
||||
grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
|
||||
|
|
@ -947,6 +956,7 @@ typedef struct {
|
|||
grpc_credentials_md_store *md_elems;
|
||||
char *service_url;
|
||||
void *user_data;
|
||||
grpc_pollset *pollset;
|
||||
grpc_credentials_metadata_cb cb;
|
||||
} grpc_composite_credentials_metadata_context;
|
||||
|
||||
|
|
@ -1015,7 +1025,8 @@ static void composite_metadata_cb(void *user_data,
|
|||
grpc_credentials *inner_creds =
|
||||
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
|
||||
if (grpc_credentials_has_request_metadata(inner_creds)) {
|
||||
grpc_credentials_get_request_metadata(inner_creds, ctx->service_url,
|
||||
grpc_credentials_get_request_metadata(inner_creds, ctx->pollset,
|
||||
ctx->service_url,
|
||||
composite_metadata_cb, ctx);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1028,6 +1039,7 @@ static void composite_metadata_cb(void *user_data,
|
|||
}
|
||||
|
||||
static void composite_get_request_metadata(grpc_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
|
|
@ -1043,11 +1055,12 @@ static void composite_get_request_metadata(grpc_credentials *creds,
|
|||
ctx->user_data = user_data;
|
||||
ctx->cb = cb;
|
||||
ctx->composite_creds = c;
|
||||
ctx->pollset = pollset;
|
||||
ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
|
||||
while (ctx->creds_index < c->inner.num_creds) {
|
||||
grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
|
||||
if (grpc_credentials_has_request_metadata(inner_creds)) {
|
||||
grpc_credentials_get_request_metadata(inner_creds, service_url,
|
||||
grpc_credentials_get_request_metadata(inner_creds, pollset, service_url,
|
||||
composite_metadata_cb, ctx);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1178,15 +1191,14 @@ static void iam_destroy(grpc_credentials *creds) {
|
|||
gpr_free(c);
|
||||
}
|
||||
|
||||
static int iam_has_request_metadata(const grpc_credentials *creds) {
|
||||
return 1;
|
||||
}
|
||||
static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
|
||||
|
||||
static int iam_has_request_metadata_only(const grpc_credentials *creds) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void iam_get_request_metadata(grpc_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ grpc_credentials_md_store *grpc_credentials_md_store_ref(
|
|||
grpc_credentials_md_store *store);
|
||||
void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
|
||||
|
||||
|
||||
/* --- grpc_credentials. --- */
|
||||
|
||||
/* It is the caller's responsibility to gpr_free the result if not NULL. */
|
||||
|
|
@ -123,7 +122,7 @@ typedef struct {
|
|||
void (*destroy)(grpc_credentials *c);
|
||||
int (*has_request_metadata)(const grpc_credentials *c);
|
||||
int (*has_request_metadata_only)(const grpc_credentials *c);
|
||||
void (*get_request_metadata)(grpc_credentials *c,
|
||||
void (*get_request_metadata)(grpc_credentials *c, grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data);
|
||||
|
|
@ -131,7 +130,6 @@ typedef struct {
|
|||
grpc_credentials *c, const char *target, const grpc_channel_args *args,
|
||||
grpc_credentials *request_metadata_creds,
|
||||
grpc_channel_security_connector **sc, grpc_channel_args **new_args);
|
||||
|
||||
} grpc_credentials_vtable;
|
||||
|
||||
struct grpc_credentials {
|
||||
|
|
@ -145,6 +143,7 @@ void grpc_credentials_unref(grpc_credentials *creds);
|
|||
int grpc_credentials_has_request_metadata(grpc_credentials *creds);
|
||||
int grpc_credentials_has_request_metadata_only(grpc_credentials *creds);
|
||||
void grpc_credentials_get_request_metadata(grpc_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data);
|
||||
|
|
@ -177,8 +176,8 @@ grpc_credentials *grpc_credentials_contains_type(
|
|||
/* Exposed for testing only. */
|
||||
grpc_credentials_status
|
||||
grpc_oauth2_token_fetcher_credentials_parse_server_response(
|
||||
const struct grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
|
||||
gpr_timespec *token_lifetime);
|
||||
const struct grpc_httpcli_response *response,
|
||||
grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
|
||||
|
||||
/* Simulates an oauth2 token fetch with the specified value for testing. */
|
||||
grpc_credentials *grpc_fake_oauth2_credentials_create(
|
||||
|
|
@ -200,4 +199,4 @@ struct grpc_server_credentials {
|
|||
grpc_security_status grpc_server_credentials_create_security_connector(
|
||||
grpc_server_credentials *creds, grpc_security_connector **sc);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
|
||||
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
|
||||
|
|
|
|||
|
|
@ -55,13 +55,10 @@ static int compute_engine_detection_done = 0;
|
|||
static gpr_mu g_mu;
|
||||
static gpr_once g_once = GPR_ONCE_INIT;
|
||||
|
||||
static void init_default_credentials(void) {
|
||||
gpr_mu_init(&g_mu);
|
||||
}
|
||||
static void init_default_credentials(void) { gpr_mu_init(&g_mu); }
|
||||
|
||||
typedef struct {
|
||||
gpr_cv cv;
|
||||
gpr_mu mu;
|
||||
grpc_pollset pollset;
|
||||
int is_done;
|
||||
int success;
|
||||
} compute_engine_detector;
|
||||
|
|
@ -82,22 +79,22 @@ static void on_compute_engine_detection_http_response(
|
|||
}
|
||||
}
|
||||
}
|
||||
gpr_mu_lock(&detector->mu);
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&detector->pollset));
|
||||
detector->is_done = 1;
|
||||
gpr_mu_unlock(&detector->mu);
|
||||
gpr_cv_signal(&detector->cv);
|
||||
grpc_pollset_kick(&detector->pollset);
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset));
|
||||
}
|
||||
|
||||
static int is_stack_running_on_compute_engine(void) {
|
||||
compute_engine_detector detector;
|
||||
grpc_httpcli_request request;
|
||||
grpc_httpcli_context context;
|
||||
|
||||
/* The http call is local. If it takes more than one sec, it is for sure not
|
||||
on compute engine. */
|
||||
gpr_timespec max_detection_delay = {1, 0};
|
||||
|
||||
gpr_mu_init(&detector.mu);
|
||||
gpr_cv_init(&detector.cv);
|
||||
grpc_pollset_init(&detector.pollset);
|
||||
detector.is_done = 0;
|
||||
detector.success = 0;
|
||||
|
||||
|
|
@ -105,19 +102,23 @@ static int is_stack_running_on_compute_engine(void) {
|
|||
request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST;
|
||||
request.path = "/";
|
||||
|
||||
grpc_httpcli_get(&request, gpr_time_add(gpr_now(), max_detection_delay),
|
||||
grpc_httpcli_context_init(&context);
|
||||
|
||||
grpc_httpcli_get(&context, &detector.pollset, &request,
|
||||
gpr_time_add(gpr_now(), max_detection_delay),
|
||||
on_compute_engine_detection_http_response, &detector);
|
||||
|
||||
/* Block until we get the response. This is not ideal but this should only be
|
||||
called once for the lifetime of the process by the default credentials. */
|
||||
gpr_mu_lock(&detector.mu);
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&detector.pollset));
|
||||
while (!detector.is_done) {
|
||||
gpr_cv_wait(&detector.cv, &detector.mu, gpr_inf_future);
|
||||
grpc_pollset_work(&detector.pollset, gpr_inf_future);
|
||||
}
|
||||
gpr_mu_unlock(&detector.mu);
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset));
|
||||
|
||||
grpc_httpcli_context_destroy(&context);
|
||||
grpc_pollset_destroy(&detector.pollset);
|
||||
|
||||
gpr_mu_destroy(&detector.mu);
|
||||
gpr_cv_destroy(&detector.cv);
|
||||
return detector.success;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -386,29 +386,13 @@ static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
|
||||
/* We bet that iterating over a handful of properties twice will be faster
|
||||
than having to realloc on average . */
|
||||
size_t auth_prop_count = 1; /* for transport_security_type. */
|
||||
grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
|
||||
size_t i;
|
||||
const char *peer_identity_property_name = NULL;
|
||||
grpc_auth_context *ctx = NULL;
|
||||
for (i = 0; i < peer->property_count; i++) {
|
||||
const tsi_peer_property *prop = &peer->properties[i];
|
||||
if (prop->name == NULL) continue;
|
||||
if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
|
||||
auth_prop_count++;
|
||||
/* If there is no subject alt name, have the CN as the identity. */
|
||||
if (peer_identity_property_name == NULL) {
|
||||
peer_identity_property_name = prop->name;
|
||||
}
|
||||
} else if (strcmp(prop->name,
|
||||
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
|
||||
auth_prop_count++;
|
||||
peer_identity_property_name = prop->name;
|
||||
}
|
||||
}
|
||||
ctx = grpc_auth_context_create(NULL, auth_prop_count);
|
||||
|
||||
/* The caller has checked the certificate type property. */
|
||||
GPR_ASSERT(peer->property_count >= 1);
|
||||
ctx = grpc_auth_context_create(NULL, peer->property_count);
|
||||
ctx->properties[0] = grpc_auth_property_init_from_cstring(
|
||||
GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
|
||||
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
|
||||
|
|
@ -417,15 +401,19 @@ static grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
|
|||
const tsi_peer_property *prop = &peer->properties[i];
|
||||
if (prop->name == NULL) continue;
|
||||
if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
|
||||
/* If there is no subject alt name, have the CN as the identity. */
|
||||
if (ctx->peer_identity_property_name == NULL) {
|
||||
ctx->peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
|
||||
}
|
||||
ctx->properties[ctx->property_count++] = grpc_auth_property_init(
|
||||
GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length);
|
||||
} else if (strcmp(prop->name,
|
||||
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
|
||||
ctx->peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
|
||||
ctx->properties[ctx->property_count++] = grpc_auth_property_init(
|
||||
GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length);
|
||||
}
|
||||
}
|
||||
GPR_ASSERT(auth_prop_count == ctx->property_count);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -203,4 +203,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
|
|||
const tsi_peer_property *tsi_peer_get_property_by_name(
|
||||
const tsi_peer *peer, const char *name);
|
||||
|
||||
/* Exposed for testing only. */
|
||||
grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ static void state_ref(grpc_server_secure_state *state) {
|
|||
|
||||
static void state_unref(grpc_server_secure_state *state) {
|
||||
if (gpr_unref(&state->refcount)) {
|
||||
/* ensure all threads have unlocked */
|
||||
gpr_mu_lock(&state->mu);
|
||||
gpr_mu_unlock(&state->mu);
|
||||
/* clean up */
|
||||
grpc_security_connector_unref(state->sc);
|
||||
gpr_free(state);
|
||||
}
|
||||
|
|
@ -124,16 +128,20 @@ static void start(grpc_server *server, void *statep, grpc_pollset **pollsets,
|
|||
grpc_tcp_server_start(state->tcp, pollsets, pollset_count, on_accept, state);
|
||||
}
|
||||
|
||||
static void destroy_done(void *statep) {
|
||||
grpc_server_secure_state *state = statep;
|
||||
grpc_server_listener_destroy_done(state->server);
|
||||
state_unref(state);
|
||||
}
|
||||
|
||||
/* Server callback: destroy the tcp listener (so we don't generate further
|
||||
callbacks) */
|
||||
static void destroy(grpc_server *server, void *statep) {
|
||||
grpc_server_secure_state *state = statep;
|
||||
gpr_mu_lock(&state->mu);
|
||||
state->is_shutdown = 1;
|
||||
grpc_tcp_server_destroy(state->tcp, grpc_server_listener_destroy_done,
|
||||
server);
|
||||
grpc_tcp_server_destroy(state->tcp, destroy_done, state);
|
||||
gpr_mu_unlock(&state->mu);
|
||||
state_unref(state);
|
||||
}
|
||||
|
||||
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include <grpc/support/log_win32.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
|
||||
#include "src/core/support/string.h"
|
||||
#include "src/core/support/string_win32.h"
|
||||
|
|
@ -93,23 +94,22 @@ void gpr_default_log(gpr_log_func_args *args) {
|
|||
|
||||
fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n",
|
||||
gpr_log_severity_string(args->severity), time_buffer,
|
||||
(int)(now.tv_nsec), GetCurrentThreadId(),
|
||||
args->file, args->line, args->message);
|
||||
(int)(now.tv_nsec), GetCurrentThreadId(), args->file, args->line,
|
||||
args->message);
|
||||
}
|
||||
|
||||
char *gpr_format_message(DWORD messageid) {
|
||||
LPTSTR tmessage;
|
||||
char *message;
|
||||
DWORD status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, messageid,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)(&tmessage), 0, NULL);
|
||||
if (status == 0) return gpr_strdup("Unable to retreive error string");
|
||||
DWORD status = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)(&tmessage), 0, NULL);
|
||||
if (status == 0) return gpr_strdup("Unable to retrieve error string");
|
||||
message = gpr_tchar_to_char(tmessage);
|
||||
LocalFree(tmessage);
|
||||
return message;
|
||||
}
|
||||
|
||||
#endif /* GPR_WIN32 */
|
||||
#endif /* GPR_WIN32 */
|
||||
|
|
|
|||
|
|
@ -118,7 +118,9 @@ void gpr_refn(gpr_refcount *r, int n) {
|
|||
}
|
||||
|
||||
int gpr_unref(gpr_refcount *r) {
|
||||
return gpr_atm_full_fetch_add(&r->count, -1) == 1;
|
||||
gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1);
|
||||
GPR_ASSERT(prior > 0);
|
||||
return prior == 1;
|
||||
}
|
||||
|
||||
void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n) {
|
||||
|
|
|
|||
|
|
@ -64,11 +64,11 @@ void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
|
|||
grpc_msg_decompress(reader->buffer_in->data.raw.compression,
|
||||
&reader->buffer_in->data.raw.slice_buffer,
|
||||
&decompressed_slices_buffer);
|
||||
reader->buffer_out = grpc_raw_byte_buffer_create(
|
||||
decompressed_slices_buffer.slices,
|
||||
decompressed_slices_buffer.count);
|
||||
reader->buffer_out =
|
||||
grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices,
|
||||
decompressed_slices_buffer.count);
|
||||
gpr_slice_buffer_destroy(&decompressed_slices_buffer);
|
||||
} else { /* not compressed, use the input buffer as output */
|
||||
} else { /* not compressed, use the input buffer as output */
|
||||
reader->buffer_out = reader->buffer_in;
|
||||
}
|
||||
reader->current.index = 0;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@ typedef enum {
|
|||
/* Status came from 'the wire' - or somewhere below the surface
|
||||
layer */
|
||||
STATUS_FROM_WIRE,
|
||||
/* Status came from the server sending status */
|
||||
STATUS_FROM_SERVER_STATUS,
|
||||
STATUS_SOURCE_COUNT
|
||||
} status_source;
|
||||
|
||||
|
|
@ -152,9 +154,13 @@ struct grpc_call {
|
|||
gpr_uint8 num_completed_requests;
|
||||
/* are we currently reading a message? */
|
||||
gpr_uint8 reading_message;
|
||||
/* have we bound a pollset yet? */
|
||||
gpr_uint8 bound_pollset;
|
||||
/* flags with bits corresponding to write states allowing us to determine
|
||||
what was sent */
|
||||
gpr_uint16 last_send_contains;
|
||||
/* cancel with this status on the next outgoing transport op */
|
||||
grpc_status_code cancel_with_status;
|
||||
|
||||
/* Active ioreqs.
|
||||
request_set and request_data contain one element per active ioreq
|
||||
|
|
@ -185,6 +191,7 @@ struct grpc_call {
|
|||
and a strong upper bound of a count of masters to be calculated. */
|
||||
gpr_uint8 request_set[GRPC_IOREQ_OP_COUNT];
|
||||
grpc_ioreq_data request_data[GRPC_IOREQ_OP_COUNT];
|
||||
gpr_uint32 request_flags[GRPC_IOREQ_OP_COUNT];
|
||||
reqinfo_master masters[GRPC_IOREQ_OP_COUNT];
|
||||
|
||||
/* Dynamic array of ioreq's that have completed: the count of
|
||||
|
|
@ -207,6 +214,9 @@ struct grpc_call {
|
|||
/* Received call statuses from various sources */
|
||||
received_status status[STATUS_SOURCE_COUNT];
|
||||
|
||||
/** Compression level for the call */
|
||||
grpc_compression_level compression_level;
|
||||
|
||||
/* Contexts for various subsystems (security, tracing, ...). */
|
||||
grpc_call_context_element context[GRPC_CONTEXT_COUNT];
|
||||
|
||||
|
|
@ -228,6 +238,7 @@ struct grpc_call {
|
|||
|
||||
gpr_slice_buffer incoming_message;
|
||||
gpr_uint32 incoming_message_length;
|
||||
gpr_uint32 incoming_message_flags;
|
||||
grpc_iomgr_closure destroy_closure;
|
||||
};
|
||||
|
||||
|
|
@ -246,8 +257,10 @@ static void execute_op(grpc_call *call, grpc_transport_op *op);
|
|||
static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata);
|
||||
static void finish_read_ops(grpc_call *call);
|
||||
static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
|
||||
const char *description,
|
||||
gpr_uint8 locked);
|
||||
const char *description);
|
||||
|
||||
static void lock(grpc_call *call);
|
||||
static void unlock(grpc_call *call);
|
||||
|
||||
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
|
||||
const void *server_transport_data,
|
||||
|
|
@ -264,6 +277,9 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
|
|||
gpr_mu_init(&call->mu);
|
||||
call->channel = channel;
|
||||
call->cq = cq;
|
||||
if (cq) {
|
||||
GRPC_CQ_INTERNAL_REF(cq, "bind");
|
||||
}
|
||||
call->is_client = server_transport_data == NULL;
|
||||
for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
|
||||
call->request_set[i] = REQSET_EMPTY;
|
||||
|
|
@ -280,7 +296,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
|
|||
}
|
||||
call->send_initial_metadata_count = add_initial_metadata_count;
|
||||
call->send_deadline = send_deadline;
|
||||
grpc_channel_internal_ref(channel);
|
||||
GRPC_CHANNEL_INTERNAL_REF(channel, "call");
|
||||
call->metadata_context = grpc_channel_get_metadata_context(channel);
|
||||
grpc_sopb_init(&call->send_ops);
|
||||
grpc_sopb_init(&call->recv_ops);
|
||||
|
|
@ -310,7 +326,12 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
|
|||
|
||||
void grpc_call_set_completion_queue(grpc_call *call,
|
||||
grpc_completion_queue *cq) {
|
||||
lock(call);
|
||||
call->cq = cq;
|
||||
if (cq) {
|
||||
GRPC_CQ_INTERNAL_REF(cq, "bind");
|
||||
}
|
||||
unlock(call);
|
||||
}
|
||||
|
||||
grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
|
||||
|
|
@ -331,7 +352,7 @@ static void destroy_call(void *call, int ignored_success) {
|
|||
size_t i;
|
||||
grpc_call *c = call;
|
||||
grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
|
||||
grpc_channel_internal_unref(c->channel);
|
||||
GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call");
|
||||
gpr_mu_destroy(&c->mu);
|
||||
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
|
||||
if (c->status[i].details) {
|
||||
|
|
@ -357,6 +378,9 @@ static void destroy_call(void *call, int ignored_success) {
|
|||
grpc_sopb_destroy(&c->recv_ops);
|
||||
grpc_bbq_destroy(&c->incoming_queue);
|
||||
gpr_slice_buffer_destroy(&c->incoming_message);
|
||||
if (c->cq) {
|
||||
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
|
||||
}
|
||||
gpr_free(c);
|
||||
}
|
||||
|
||||
|
|
@ -381,6 +405,8 @@ void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) {
|
|||
|
||||
static void set_status_code(grpc_call *call, status_source source,
|
||||
gpr_uint32 status) {
|
||||
if (call->status[source].is_set) return;
|
||||
|
||||
call->status[source].is_set = 1;
|
||||
call->status[source].code = status;
|
||||
|
||||
|
|
@ -389,6 +415,11 @@ static void set_status_code(grpc_call *call, status_source source,
|
|||
}
|
||||
}
|
||||
|
||||
static void set_decode_compression_level(grpc_call *call,
|
||||
grpc_compression_level clevel) {
|
||||
call->compression_level = clevel;
|
||||
}
|
||||
|
||||
static void set_status_details(grpc_call *call, status_source source,
|
||||
grpc_mdstr *status) {
|
||||
if (call->status[source].details != NULL) {
|
||||
|
|
@ -409,6 +440,7 @@ static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); }
|
|||
|
||||
static int need_more_data(grpc_call *call) {
|
||||
if (call->read_state == READ_STATE_STREAM_CLOSED) return 0;
|
||||
/* TODO(ctiller): this needs some serious cleanup */
|
||||
return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) ||
|
||||
(is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) &&
|
||||
grpc_bbq_empty(&call->incoming_queue)) ||
|
||||
|
|
@ -417,7 +449,8 @@ static int need_more_data(grpc_call *call) {
|
|||
is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) ||
|
||||
(is_op_live(call, GRPC_IOREQ_RECV_CLOSE) &&
|
||||
grpc_bbq_empty(&call->incoming_queue)) ||
|
||||
(call->write_state == WRITE_STATE_INITIAL && !call->is_client);
|
||||
(call->write_state == WRITE_STATE_INITIAL && !call->is_client) ||
|
||||
(call->cancel_with_status != GRPC_STATUS_OK);
|
||||
}
|
||||
|
||||
static void unlock(grpc_call *call) {
|
||||
|
|
@ -429,6 +462,10 @@ static void unlock(grpc_call *call) {
|
|||
|
||||
memset(&op, 0, sizeof(op));
|
||||
|
||||
op.cancel_with_status = call->cancel_with_status;
|
||||
start_op = op.cancel_with_status != GRPC_STATUS_OK;
|
||||
call->cancel_with_status = GRPC_STATUS_OK; /* reset */
|
||||
|
||||
if (!call->receiving && need_more_data(call)) {
|
||||
op.recv_ops = &call->recv_ops;
|
||||
op.recv_state = &call->recv_state;
|
||||
|
|
@ -447,6 +484,12 @@ static void unlock(grpc_call *call) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!call->bound_pollset && call->cq && (!call->is_client || start_op)) {
|
||||
call->bound_pollset = 1;
|
||||
op.bind_pollset = grpc_cq_pollset(call->cq);
|
||||
start_op = 1;
|
||||
}
|
||||
|
||||
if (!call->completing && call->num_completed_requests != 0) {
|
||||
completing_requests = call->num_completed_requests;
|
||||
memcpy(completed_requests, call->completed_requests,
|
||||
|
|
@ -549,10 +592,18 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
|
|||
call->write_state = WRITE_STATE_WRITE_CLOSED;
|
||||
}
|
||||
break;
|
||||
case GRPC_IOREQ_SEND_STATUS:
|
||||
if (call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details !=
|
||||
NULL) {
|
||||
grpc_mdstr_unref(
|
||||
call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details);
|
||||
call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details =
|
||||
NULL;
|
||||
}
|
||||
break;
|
||||
case GRPC_IOREQ_RECV_CLOSE:
|
||||
case GRPC_IOREQ_SEND_INITIAL_METADATA:
|
||||
case GRPC_IOREQ_SEND_TRAILING_METADATA:
|
||||
case GRPC_IOREQ_SEND_STATUS:
|
||||
case GRPC_IOREQ_SEND_CLOSE:
|
||||
break;
|
||||
case GRPC_IOREQ_RECV_STATUS:
|
||||
|
|
@ -653,7 +704,7 @@ static int begin_message(grpc_call *call, grpc_begin_message msg) {
|
|||
gpr_asprintf(
|
||||
&message, "Message terminated early; read %d bytes, expected %d",
|
||||
(int)call->incoming_message.length, (int)call->incoming_message_length);
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message, 1);
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
|
||||
gpr_free(message);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -664,12 +715,13 @@ static int begin_message(grpc_call *call, grpc_begin_message msg) {
|
|||
&message,
|
||||
"Maximum message length of %d exceeded by a message of length %d",
|
||||
grpc_channel_get_max_message_length(call->channel), msg.length);
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message, 1);
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
|
||||
gpr_free(message);
|
||||
return 0;
|
||||
} else if (msg.length > 0) {
|
||||
call->reading_message = 1;
|
||||
call->incoming_message_length = msg.length;
|
||||
call->incoming_message_flags = msg.flags;
|
||||
return 1;
|
||||
} else {
|
||||
finish_message(call);
|
||||
|
|
@ -685,7 +737,7 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
|
|||
/* we have to be reading a message to know what to do here */
|
||||
if (!call->reading_message) {
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT,
|
||||
"Received payload data while not reading a message", 1);
|
||||
"Received payload data while not reading a message");
|
||||
return 0;
|
||||
}
|
||||
/* append the slice to the incoming buffer */
|
||||
|
|
@ -696,7 +748,7 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
|
|||
gpr_asprintf(
|
||||
&message, "Receiving message overflow; read %d bytes, expected %d",
|
||||
(int)call->incoming_message.length, (int)call->incoming_message_length);
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message, 1);
|
||||
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
|
||||
gpr_free(message);
|
||||
return 0;
|
||||
} else if (call->incoming_message.length == call->incoming_message_length) {
|
||||
|
|
@ -818,6 +870,7 @@ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
|
|||
|
||||
static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
|
||||
grpc_ioreq_data data;
|
||||
gpr_uint32 flags;
|
||||
grpc_metadata_batch mdb;
|
||||
size_t i;
|
||||
GPR_ASSERT(op->send_ops == NULL);
|
||||
|
|
@ -837,15 +890,15 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
|
|||
}
|
||||
grpc_sopb_add_metadata(&call->send_ops, mdb);
|
||||
op->send_ops = &call->send_ops;
|
||||
op->bind_pollset = grpc_cq_pollset(call->cq);
|
||||
call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA;
|
||||
call->send_initial_metadata_count = 0;
|
||||
/* fall through intended */
|
||||
case WRITE_STATE_STARTED:
|
||||
if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) {
|
||||
data = call->request_data[GRPC_IOREQ_SEND_MESSAGE];
|
||||
flags = call->request_flags[GRPC_IOREQ_SEND_MESSAGE];
|
||||
grpc_sopb_add_begin_message(
|
||||
&call->send_ops, grpc_byte_buffer_length(data.send_message), 0);
|
||||
&call->send_ops, grpc_byte_buffer_length(data.send_message), flags);
|
||||
copy_byte_buffer_to_stream_ops(data.send_message, &call->send_ops);
|
||||
op->send_ops = &call->send_ops;
|
||||
call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE;
|
||||
|
|
@ -875,8 +928,9 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
|
|||
call->metadata_context,
|
||||
grpc_mdstr_ref(
|
||||
grpc_channel_get_message_string(call->channel)),
|
||||
grpc_mdstr_from_string(call->metadata_context,
|
||||
data.send_status.details)));
|
||||
data.send_status.details));
|
||||
call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details =
|
||||
NULL;
|
||||
}
|
||||
grpc_sopb_add_metadata(&call->send_ops, mdb);
|
||||
}
|
||||
|
|
@ -976,9 +1030,18 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
|
|||
GRPC_CALL_ERROR_INVALID_METADATA);
|
||||
}
|
||||
}
|
||||
if (op == GRPC_IOREQ_SEND_STATUS) {
|
||||
set_status_code(call, STATUS_FROM_SERVER_STATUS,
|
||||
reqs[i].data.send_status.code);
|
||||
if (reqs[i].data.send_status.details) {
|
||||
set_status_details(call, STATUS_FROM_SERVER_STATUS,
|
||||
grpc_mdstr_ref(reqs[i].data.send_status.details));
|
||||
}
|
||||
}
|
||||
have_ops |= 1u << op;
|
||||
|
||||
call->request_data[op] = data;
|
||||
call->request_flags[op] = reqs[i].flags;
|
||||
call->request_set[op] = set;
|
||||
}
|
||||
|
||||
|
|
@ -1025,35 +1088,43 @@ grpc_call_error grpc_call_cancel(grpc_call *call) {
|
|||
grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
|
||||
grpc_status_code status,
|
||||
const char *description) {
|
||||
return cancel_with_status(c, status, description, 0);
|
||||
grpc_call_error r;
|
||||
lock(c);
|
||||
r = cancel_with_status(c, status, description);
|
||||
unlock(c);
|
||||
return r;
|
||||
}
|
||||
|
||||
static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
|
||||
const char *description,
|
||||
gpr_uint8 locked) {
|
||||
grpc_transport_op op;
|
||||
const char *description) {
|
||||
grpc_mdstr *details =
|
||||
description ? grpc_mdstr_from_string(c->metadata_context, description)
|
||||
: NULL;
|
||||
memset(&op, 0, sizeof(op));
|
||||
op.cancel_with_status = status;
|
||||
|
||||
if (locked == 0) {
|
||||
lock(c);
|
||||
}
|
||||
GPR_ASSERT(status != GRPC_STATUS_OK);
|
||||
|
||||
set_status_code(c, STATUS_FROM_API_OVERRIDE, status);
|
||||
set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
|
||||
if (locked == 0) {
|
||||
unlock(c);
|
||||
}
|
||||
|
||||
execute_op(c, &op);
|
||||
c->cancel_with_status = status;
|
||||
|
||||
return GRPC_CALL_OK;
|
||||
}
|
||||
|
||||
static void finished_loose_op(void *call, int success_ignored) {
|
||||
GRPC_CALL_INTERNAL_UNREF(call, "loose-op", 0);
|
||||
}
|
||||
|
||||
static void execute_op(grpc_call *call, grpc_transport_op *op) {
|
||||
grpc_call_element *elem;
|
||||
|
||||
GPR_ASSERT(op->on_consumed == NULL);
|
||||
if (op->cancel_with_status != GRPC_STATUS_OK || op->bind_pollset) {
|
||||
GRPC_CALL_INTERNAL_REF(call, "loose-op");
|
||||
op->on_consumed = finished_loose_op;
|
||||
op->on_consumed_user_data = call;
|
||||
}
|
||||
|
||||
elem = CALL_ELEM_FROM_CALL(call, 0);
|
||||
op->context = call->context;
|
||||
elem->filter->start_transport_op(elem, op);
|
||||
|
|
@ -1066,12 +1137,10 @@ grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
|
|||
static void call_alarm(void *arg, int success) {
|
||||
grpc_call *call = arg;
|
||||
if (success) {
|
||||
if (call->is_client) {
|
||||
cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
|
||||
"Deadline Exceeded", 0);
|
||||
} else {
|
||||
grpc_call_cancel(call);
|
||||
}
|
||||
lock(call);
|
||||
cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
|
||||
"Deadline Exceeded");
|
||||
unlock(call);
|
||||
}
|
||||
GRPC_CALL_INTERNAL_UNREF(call, "alarm", 1);
|
||||
}
|
||||
|
|
@ -1110,6 +1179,28 @@ static gpr_uint32 decode_status(grpc_mdelem *md) {
|
|||
return status;
|
||||
}
|
||||
|
||||
/* just as for status above, we need to offset: metadata userdata can't hold a
|
||||
* zero (null), which in this case is used to signal no compression */
|
||||
#define COMPRESS_OFFSET 1
|
||||
static void destroy_compression(void *ignored) {}
|
||||
|
||||
static gpr_uint32 decode_compression(grpc_mdelem *md) {
|
||||
grpc_compression_level clevel;
|
||||
void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
|
||||
if (user_data) {
|
||||
clevel = ((grpc_compression_level)(gpr_intptr)user_data) - COMPRESS_OFFSET;
|
||||
} else {
|
||||
if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
|
||||
GPR_SLICE_LENGTH(md->value->slice),
|
||||
&clevel)) {
|
||||
clevel = GRPC_COMPRESS_LEVEL_NONE; /* could not parse, no compression */
|
||||
}
|
||||
grpc_mdelem_set_user_data(md, destroy_compression,
|
||||
(void *)(gpr_intptr)(clevel + COMPRESS_OFFSET));
|
||||
}
|
||||
return clevel;
|
||||
}
|
||||
|
||||
static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
|
||||
grpc_linked_mdelem *l;
|
||||
grpc_metadata_array *dest;
|
||||
|
|
@ -1125,6 +1216,8 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
|
|||
set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
|
||||
} else if (key == grpc_channel_get_message_string(call->channel)) {
|
||||
set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
|
||||
} else if (key == grpc_channel_get_compresssion_level_string(call->channel)) {
|
||||
set_decode_compression_level(call, decode_compression(md));
|
||||
} else {
|
||||
dest = &call->buffered_metadata[is_trailing];
|
||||
if (dest->count == dest->capacity) {
|
||||
|
|
@ -1189,6 +1282,14 @@ static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
|
|||
grpc_cq_end_op(call->cq, tag, call, 1);
|
||||
}
|
||||
|
||||
static int are_write_flags_valid(gpr_uint32 flags) {
|
||||
/* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
|
||||
const gpr_uint32 allowed_write_positions =
|
||||
(GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK);
|
||||
const gpr_uint32 invalid_positions = ~allowed_write_positions;
|
||||
return !(flags & invalid_positions);
|
||||
}
|
||||
|
||||
grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
|
||||
size_t nops, void *tag) {
|
||||
grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT];
|
||||
|
|
@ -1211,30 +1312,43 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
|
|||
op = &ops[in];
|
||||
switch (op->op) {
|
||||
case GRPC_OP_SEND_INITIAL_METADATA:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_SEND_INITIAL_METADATA;
|
||||
req->data.send_metadata.count = op->data.send_initial_metadata.count;
|
||||
req->data.send_metadata.metadata =
|
||||
op->data.send_initial_metadata.metadata;
|
||||
req->flags = op->flags;
|
||||
break;
|
||||
case GRPC_OP_SEND_MESSAGE:
|
||||
if (!are_write_flags_valid(op->flags)) {
|
||||
return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
}
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_SEND_MESSAGE;
|
||||
req->data.send_message = op->data.send_message;
|
||||
req->flags = ops->flags;
|
||||
break;
|
||||
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
if (!call->is_client) {
|
||||
return GRPC_CALL_ERROR_NOT_ON_SERVER;
|
||||
}
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_SEND_CLOSE;
|
||||
req->flags = op->flags;
|
||||
break;
|
||||
case GRPC_OP_SEND_STATUS_FROM_SERVER:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
if (call->is_client) {
|
||||
return GRPC_CALL_ERROR_NOT_ON_CLIENT;
|
||||
}
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_SEND_TRAILING_METADATA;
|
||||
req->flags = op->flags;
|
||||
req->data.send_metadata.count =
|
||||
op->data.send_status_from_server.trailing_metadata_count;
|
||||
req->data.send_metadata.metadata =
|
||||
|
|
@ -1243,29 +1357,42 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
|
|||
req->op = GRPC_IOREQ_SEND_STATUS;
|
||||
req->data.send_status.code = op->data.send_status_from_server.status;
|
||||
req->data.send_status.details =
|
||||
op->data.send_status_from_server.status_details;
|
||||
op->data.send_status_from_server.status_details != NULL
|
||||
? grpc_mdstr_from_string(
|
||||
call->metadata_context,
|
||||
op->data.send_status_from_server.status_details)
|
||||
: NULL;
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_SEND_CLOSE;
|
||||
break;
|
||||
case GRPC_OP_RECV_INITIAL_METADATA:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
if (!call->is_client) {
|
||||
return GRPC_CALL_ERROR_NOT_ON_SERVER;
|
||||
}
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
|
||||
req->data.recv_metadata = op->data.recv_initial_metadata;
|
||||
req->flags = op->flags;
|
||||
break;
|
||||
case GRPC_OP_RECV_MESSAGE:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_RECV_MESSAGE;
|
||||
req->data.recv_message = op->data.recv_message;
|
||||
req->flags = op->flags;
|
||||
break;
|
||||
case GRPC_OP_RECV_STATUS_ON_CLIENT:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
if (!call->is_client) {
|
||||
return GRPC_CALL_ERROR_NOT_ON_SERVER;
|
||||
}
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_RECV_STATUS;
|
||||
req->flags = op->flags;
|
||||
req->data.recv_status.set_value = set_status_value_directly;
|
||||
req->data.recv_status.user_data = op->data.recv_status_on_client.status;
|
||||
req = &reqs[out++];
|
||||
|
|
@ -1283,8 +1410,11 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
|
|||
finish_func = finish_batch_with_close;
|
||||
break;
|
||||
case GRPC_OP_RECV_CLOSE_ON_SERVER:
|
||||
/* Flag validation: currently allow no flags */
|
||||
if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS;
|
||||
req = &reqs[out++];
|
||||
req->op = GRPC_IOREQ_RECV_STATUS;
|
||||
req->flags = op->flags;
|
||||
req->data.recv_status.set_value = set_cancelled_value;
|
||||
req->data.recv_status.user_data =
|
||||
op->data.recv_close_on_server.cancelled;
|
||||
|
|
|
|||
|
|
@ -72,13 +72,14 @@ typedef union {
|
|||
grpc_byte_buffer *send_message;
|
||||
struct {
|
||||
grpc_status_code code;
|
||||
const char *details;
|
||||
grpc_mdstr *details;
|
||||
} send_status;
|
||||
} grpc_ioreq_data;
|
||||
|
||||
typedef struct {
|
||||
grpc_ioreq_op op;
|
||||
grpc_ioreq_data data;
|
||||
gpr_uint32 flags; /**< A copy of the write flags from grpc_op */
|
||||
} grpc_ioreq;
|
||||
|
||||
typedef void (*grpc_ioreq_completion_func)(grpc_call *call, int success,
|
||||
|
|
@ -95,8 +96,10 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call);
|
|||
|
||||
#ifdef GRPC_CALL_REF_COUNT_DEBUG
|
||||
void grpc_call_internal_ref(grpc_call *call, const char *reason);
|
||||
void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion);
|
||||
#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call, reason)
|
||||
void grpc_call_internal_unref(grpc_call *call, const char *reason,
|
||||
int allow_immediate_deletion);
|
||||
#define GRPC_CALL_INTERNAL_REF(call, reason) \
|
||||
grpc_call_internal_ref(call, reason)
|
||||
#define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) \
|
||||
grpc_call_internal_unref(call, reason, allow_immediate_deletion)
|
||||
#else
|
||||
|
|
@ -124,8 +127,7 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
|
|||
|
||||
void grpc_server_log_request_call(char *file, int line,
|
||||
gpr_log_severity severity,
|
||||
grpc_server *server,
|
||||
grpc_call **call,
|
||||
grpc_server *server, grpc_call **call,
|
||||
grpc_call_details *details,
|
||||
grpc_metadata_array *initial_metadata,
|
||||
grpc_completion_queue *cq_bound_to_call,
|
||||
|
|
@ -134,16 +136,20 @@ void grpc_server_log_request_call(char *file, int line,
|
|||
|
||||
/* Set a context pointer.
|
||||
No thread safety guarantees are made wrt this value. */
|
||||
void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value,
|
||||
void (*destroy)(void *value));
|
||||
void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
|
||||
void *value, void (*destroy)(void *value));
|
||||
/* Get a context pointer. */
|
||||
void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
|
||||
|
||||
#define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \
|
||||
if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag)
|
||||
|
||||
#define GRPC_SERVER_LOG_REQUEST_CALL(sev, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notifications, tag) \
|
||||
if (grpc_trace_batch) grpc_server_log_request_call(sev, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notifications, tag)
|
||||
#define GRPC_SERVER_LOG_REQUEST_CALL(sev, server, call, details, \
|
||||
initial_metadata, cq_bound_to_call, \
|
||||
cq_for_notifications, tag) \
|
||||
if (grpc_trace_batch) \
|
||||
grpc_server_log_request_call(sev, server, call, details, initial_metadata, \
|
||||
cq_bound_to_call, cq_for_notifications, tag)
|
||||
|
||||
gpr_uint8 grpc_call_is_client(grpc_call *call);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ struct grpc_channel {
|
|||
grpc_mdctx *metadata_context;
|
||||
/** mdstr for the grpc-status key */
|
||||
grpc_mdstr *grpc_status_string;
|
||||
grpc_mdstr *grpc_compression_level_string;
|
||||
grpc_mdstr *grpc_message_string;
|
||||
grpc_mdstr *path_string;
|
||||
grpc_mdstr *authority_string;
|
||||
|
|
@ -98,6 +99,8 @@ grpc_channel *grpc_channel_create_from_filters(
|
|||
gpr_ref_init(&channel->refs, 1 + is_client);
|
||||
channel->metadata_context = mdctx;
|
||||
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
|
||||
channel->grpc_compression_level_string =
|
||||
grpc_mdstr_from_string(mdctx, "grpc-compression-level");
|
||||
channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
|
||||
for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
|
||||
char buf[GPR_LTOA_MIN_BUFSIZE];
|
||||
|
|
@ -187,8 +190,14 @@ grpc_call *grpc_channel_create_registered_call(
|
|||
grpc_mdelem_ref(rc->authority), deadline);
|
||||
}
|
||||
|
||||
void grpc_channel_internal_ref(grpc_channel *channel) {
|
||||
gpr_ref(&channel->refs);
|
||||
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
|
||||
void grpc_channel_internal_ref(grpc_channel *c, const char *reason) {
|
||||
gpr_log(GPR_DEBUG, "CHANNEL: ref %p %d -> %d [%s]", c, c->refs.count,
|
||||
c->refs.count + 1, reason);
|
||||
#else
|
||||
void grpc_channel_internal_ref(grpc_channel *c) {
|
||||
#endif
|
||||
gpr_ref(&c->refs);
|
||||
}
|
||||
|
||||
static void destroy_channel(void *p, int ok) {
|
||||
|
|
@ -199,6 +208,7 @@ static void destroy_channel(void *p, int ok) {
|
|||
grpc_mdelem_unref(channel->grpc_status_elem[i]);
|
||||
}
|
||||
grpc_mdstr_unref(channel->grpc_status_string);
|
||||
grpc_mdstr_unref(channel->grpc_compression_level_string);
|
||||
grpc_mdstr_unref(channel->grpc_message_string);
|
||||
grpc_mdstr_unref(channel->path_string);
|
||||
grpc_mdstr_unref(channel->authority_string);
|
||||
|
|
@ -214,7 +224,13 @@ static void destroy_channel(void *p, int ok) {
|
|||
gpr_free(channel);
|
||||
}
|
||||
|
||||
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
|
||||
void grpc_channel_internal_unref(grpc_channel *channel, const char *reason) {
|
||||
gpr_log(GPR_DEBUG, "CHANNEL: unref %p %d -> %d [%s]", channel,
|
||||
channel->refs.count, channel->refs.count - 1, reason);
|
||||
#else
|
||||
void grpc_channel_internal_unref(grpc_channel *channel) {
|
||||
#endif
|
||||
if (gpr_unref(&channel->refs)) {
|
||||
channel->destroy_closure.cb = destroy_channel;
|
||||
channel->destroy_closure.cb_arg = channel;
|
||||
|
|
@ -238,11 +254,11 @@ void grpc_channel_destroy(grpc_channel *channel) {
|
|||
op.dir = GRPC_CALL_DOWN;
|
||||
elem->filter->channel_op(elem, NULL, &op);
|
||||
|
||||
grpc_channel_internal_unref(channel);
|
||||
GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
|
||||
}
|
||||
|
||||
void grpc_client_channel_closed(grpc_channel_element *elem) {
|
||||
grpc_channel_internal_unref(CHANNEL_FROM_TOP_ELEM(elem));
|
||||
GRPC_CHANNEL_INTERNAL_UNREF(CHANNEL_FROM_TOP_ELEM(elem), "closed");
|
||||
}
|
||||
|
||||
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
|
||||
|
|
@ -257,6 +273,11 @@ grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) {
|
|||
return channel->grpc_status_string;
|
||||
}
|
||||
|
||||
grpc_mdstr *grpc_channel_get_compresssion_level_string(grpc_channel *channel) {
|
||||
return channel->grpc_compression_level_string;
|
||||
}
|
||||
|
||||
|
||||
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
|
||||
if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
|
||||
return grpc_mdelem_ref(channel->grpc_status_elem[i]);
|
||||
|
|
|
|||
|
|
@ -53,12 +53,26 @@ grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
|
|||
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
|
||||
int status_code);
|
||||
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
|
||||
grpc_mdstr *grpc_channel_get_compresssion_level_string(grpc_channel *channel);
|
||||
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
|
||||
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
|
||||
|
||||
void grpc_client_channel_closed(grpc_channel_element *elem);
|
||||
|
||||
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
|
||||
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
|
||||
void grpc_channel_internal_unref(grpc_channel *channel, const char *reason);
|
||||
#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
|
||||
grpc_channel_internal_ref(channel, reason)
|
||||
#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
|
||||
grpc_channel_internal_unref(channel, reason)
|
||||
#else
|
||||
void grpc_channel_internal_ref(grpc_channel *channel);
|
||||
void grpc_channel_internal_unref(grpc_channel *channel);
|
||||
#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
|
||||
grpc_channel_internal_ref(channel)
|
||||
#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
|
||||
grpc_channel_internal_unref(channel)
|
||||
#endif
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ static void done(request *r, int was_successful) {
|
|||
static void on_connect(void *rp, grpc_endpoint *tcp) {
|
||||
request *r = rp;
|
||||
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request)) {
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request, "on_connect")) {
|
||||
if (tcp) {
|
||||
grpc_endpoint_shutdown(tcp);
|
||||
grpc_endpoint_destroy(tcp);
|
||||
|
|
@ -107,12 +107,12 @@ static void on_connect(void *rp, grpc_endpoint *tcp) {
|
|||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (grpc_client_setup_cb_begin(r->cs_request)) {
|
||||
} else if (grpc_client_setup_cb_begin(r->cs_request, "on_connect")) {
|
||||
grpc_create_chttp2_transport(
|
||||
r->setup->setup_callback, r->setup->setup_user_data,
|
||||
grpc_client_setup_get_channel_args(r->cs_request), tcp, NULL, 0,
|
||||
grpc_client_setup_get_mdctx(r->cs_request), 1);
|
||||
grpc_client_setup_cb_end(r->cs_request);
|
||||
grpc_client_setup_cb_end(r->cs_request, "on_connect");
|
||||
done(r, 1);
|
||||
return;
|
||||
} else {
|
||||
|
|
@ -126,9 +126,10 @@ static int maybe_try_next_resolved(request *r) {
|
|||
if (!r->resolved) return 0;
|
||||
if (r->resolved_index == r->resolved->naddrs) return 0;
|
||||
addr = &r->resolved->addrs[r->resolved_index++];
|
||||
grpc_tcp_client_connect(on_connect, r, (struct sockaddr *)&addr->addr,
|
||||
addr->len,
|
||||
grpc_client_setup_request_deadline(r->cs_request));
|
||||
grpc_tcp_client_connect(
|
||||
on_connect, r, grpc_client_setup_get_interested_parties(r->cs_request),
|
||||
(struct sockaddr *)&addr->addr, addr->len,
|
||||
grpc_client_setup_request_deadline(r->cs_request));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +138,8 @@ static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
|
|||
request *r = rp;
|
||||
|
||||
/* if we're not still the active request, abort */
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request)) {
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request,
|
||||
"on_resolved")) {
|
||||
if (resolved) {
|
||||
grpc_resolved_addresses_destroy(resolved);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,9 +59,6 @@ typedef struct event {
|
|||
|
||||
/* Completion queue structure */
|
||||
struct grpc_completion_queue {
|
||||
/* TODO(ctiller): see if this can be removed */
|
||||
int allow_polling;
|
||||
|
||||
/* When refs drops to zero, we are in shutdown mode, and will be destroyable
|
||||
once all queued events are drained */
|
||||
gpr_refcount refs;
|
||||
|
|
@ -76,6 +73,7 @@ struct grpc_completion_queue {
|
|||
event *queue;
|
||||
/* Fixed size chained hash table of events for pluck() */
|
||||
event *buckets[NUM_TAG_BUCKETS];
|
||||
int is_server_cq;
|
||||
};
|
||||
|
||||
grpc_completion_queue *grpc_completion_queue_create(void) {
|
||||
|
|
@ -83,33 +81,41 @@ grpc_completion_queue *grpc_completion_queue_create(void) {
|
|||
memset(cc, 0, sizeof(*cc));
|
||||
/* Initial ref is dropped by grpc_completion_queue_shutdown */
|
||||
gpr_ref_init(&cc->refs, 1);
|
||||
gpr_ref_init(&cc->owning_refs, 1);
|
||||
/* One for destroy(), one for pollset_shutdown */
|
||||
gpr_ref_init(&cc->owning_refs, 2);
|
||||
grpc_pollset_init(&cc->pollset);
|
||||
cc->allow_polling = 1;
|
||||
return cc;
|
||||
}
|
||||
|
||||
#ifdef GRPC_CQ_REF_COUNT_DEBUG
|
||||
void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason) {
|
||||
gpr_log(GPR_DEBUG, "CQ:%p ref %d -> %d %s", cc, (int)cc->owning_refs.count,
|
||||
(int)cc->owning_refs.count + 1, reason);
|
||||
#else
|
||||
void grpc_cq_internal_ref(grpc_completion_queue *cc) {
|
||||
#endif
|
||||
gpr_ref(&cc->owning_refs);
|
||||
}
|
||||
|
||||
static void on_pollset_destroy_done(void *arg) {
|
||||
grpc_completion_queue *cc = arg;
|
||||
grpc_pollset_destroy(&cc->pollset);
|
||||
gpr_free(cc);
|
||||
GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy");
|
||||
}
|
||||
|
||||
#ifdef GRPC_CQ_REF_COUNT_DEBUG
|
||||
void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason) {
|
||||
gpr_log(GPR_DEBUG, "CQ:%p unref %d -> %d %s", cc, (int)cc->owning_refs.count,
|
||||
(int)cc->owning_refs.count - 1, reason);
|
||||
#else
|
||||
void grpc_cq_internal_unref(grpc_completion_queue *cc) {
|
||||
#endif
|
||||
if (gpr_unref(&cc->owning_refs)) {
|
||||
GPR_ASSERT(cc->queue == NULL);
|
||||
grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
|
||||
grpc_pollset_destroy(&cc->pollset);
|
||||
gpr_free(cc);
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc) {
|
||||
cc->allow_polling = 0;
|
||||
}
|
||||
|
||||
/* Create and append an event to the queue. Returns the event so that its data
|
||||
members can be filled in.
|
||||
Requires GRPC_POLLSET_MU(&cc->pollset) locked. */
|
||||
|
|
@ -133,7 +139,6 @@ static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type,
|
|||
ev->bucket_prev = cc->buckets[bucket]->bucket_prev;
|
||||
ev->bucket_next->bucket_prev = ev->bucket_prev->bucket_next = ev;
|
||||
}
|
||||
gpr_cv_broadcast(GRPC_POLLSET_CV(&cc->pollset));
|
||||
grpc_pollset_kick(&cc->pollset);
|
||||
return ev;
|
||||
}
|
||||
|
|
@ -145,25 +150,24 @@ void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call) {
|
|||
|
||||
/* Signal the end of an operation - if this is the last waiting-to-be-queued
|
||||
event, then enter shutdown mode */
|
||||
static void end_op_locked(grpc_completion_queue *cc,
|
||||
grpc_completion_type type) {
|
||||
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
|
||||
int success) {
|
||||
event *ev;
|
||||
int shutdown = 0;
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
ev = add_locked(cc, GRPC_OP_COMPLETE, tag, call);
|
||||
ev->base.success = success;
|
||||
if (gpr_unref(&cc->refs)) {
|
||||
GPR_ASSERT(!cc->shutdown);
|
||||
GPR_ASSERT(cc->shutdown_called);
|
||||
cc->shutdown = 1;
|
||||
gpr_cv_broadcast(GRPC_POLLSET_CV(&cc->pollset));
|
||||
shutdown = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
|
||||
int success) {
|
||||
event *ev;
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
ev = add_locked(cc, GRPC_OP_COMPLETE, tag, call);
|
||||
ev->base.success = success;
|
||||
end_op_locked(cc, GRPC_OP_COMPLETE);
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
if (call) GRPC_CALL_INTERNAL_UNREF(call, "cq", 0);
|
||||
if (shutdown) {
|
||||
grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a GRPC_QUEUE_SHUTDOWN event without queuing it anywhere */
|
||||
|
|
@ -179,6 +183,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
|
|||
event *ev = NULL;
|
||||
grpc_event ret;
|
||||
|
||||
GRPC_CQ_INTERNAL_REF(cc, "next");
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
for (;;) {
|
||||
if (cc->queue != NULL) {
|
||||
|
|
@ -205,15 +210,12 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
|
|||
ev = create_shutdown_event();
|
||||
break;
|
||||
}
|
||||
if (cc->allow_polling && grpc_pollset_work(&cc->pollset, deadline)) {
|
||||
continue;
|
||||
}
|
||||
if (gpr_cv_wait(GRPC_POLLSET_CV(&cc->pollset),
|
||||
GRPC_POLLSET_MU(&cc->pollset), deadline)) {
|
||||
if (!grpc_pollset_work(&cc->pollset, deadline)) {
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
ret.type = GRPC_QUEUE_TIMEOUT;
|
||||
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
|
||||
GRPC_CQ_INTERNAL_UNREF(cc, "next");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -221,6 +223,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
|
|||
ret = ev->base;
|
||||
gpr_free(ev);
|
||||
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
|
||||
GRPC_CQ_INTERNAL_UNREF(cc, "next");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -258,6 +261,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
|
|||
event *ev = NULL;
|
||||
grpc_event ret;
|
||||
|
||||
GRPC_CQ_INTERNAL_REF(cc, "pluck");
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
for (;;) {
|
||||
if ((ev = pluck_event(cc, tag))) {
|
||||
|
|
@ -267,15 +271,12 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
|
|||
ev = create_shutdown_event();
|
||||
break;
|
||||
}
|
||||
if (cc->allow_polling && grpc_pollset_work(&cc->pollset, deadline)) {
|
||||
continue;
|
||||
}
|
||||
if (gpr_cv_wait(GRPC_POLLSET_CV(&cc->pollset),
|
||||
GRPC_POLLSET_MU(&cc->pollset), deadline)) {
|
||||
if (!grpc_pollset_work(&cc->pollset, deadline)) {
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
ret.type = GRPC_QUEUE_TIMEOUT;
|
||||
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
|
||||
GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -283,6 +284,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
|
|||
ret = ev->base;
|
||||
gpr_free(ev);
|
||||
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
|
||||
GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -290,6 +292,10 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
|
|||
to zero here, then enter shutdown mode and wake up any waiters */
|
||||
void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
|
||||
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
if (cc->shutdown_called) {
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
return;
|
||||
}
|
||||
cc->shutdown_called = 1;
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
|
||||
|
|
@ -297,13 +303,14 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
|
|||
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
GPR_ASSERT(!cc->shutdown);
|
||||
cc->shutdown = 1;
|
||||
gpr_cv_broadcast(GRPC_POLLSET_CV(&cc->pollset));
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
|
||||
grpc_cq_internal_unref(cc);
|
||||
grpc_completion_queue_shutdown(cc);
|
||||
GRPC_CQ_INTERNAL_UNREF(cc, "destroy");
|
||||
}
|
||||
|
||||
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
|
||||
|
|
@ -317,3 +324,7 @@ void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc) {
|
|||
gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
|
||||
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
|
||||
}
|
||||
|
||||
void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; }
|
||||
|
||||
int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; }
|
||||
|
|
|
|||
|
|
@ -39,8 +39,17 @@
|
|||
#include "src/core/iomgr/pollset.h"
|
||||
#include <grpc/grpc.h>
|
||||
|
||||
#ifdef GRPC_CQ_REF_COUNT_DEBUG
|
||||
void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason);
|
||||
void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason);
|
||||
#define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc, reason)
|
||||
#define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc, reason)
|
||||
#else
|
||||
void grpc_cq_internal_ref(grpc_completion_queue *cc);
|
||||
void grpc_cq_internal_unref(grpc_completion_queue *cc);
|
||||
#define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc)
|
||||
#define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc)
|
||||
#endif
|
||||
|
||||
/* Flag that an operation is beginning: the completion channel will not finish
|
||||
shutdown until a corrensponding grpc_cq_end_* call is made */
|
||||
|
|
@ -50,11 +59,11 @@ void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call);
|
|||
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
|
||||
int success);
|
||||
|
||||
/* disable polling for some tests */
|
||||
void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc);
|
||||
|
||||
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
|
||||
|
||||
void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc);
|
||||
|
||||
void grpc_cq_mark_server_cq(grpc_completion_queue *cc);
|
||||
int grpc_cq_is_server_cq(grpc_completion_queue *cc);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ static void lame_start_transport_op(grpc_call_element *elem,
|
|||
*op->recv_state = GRPC_STREAM_CLOSED;
|
||||
op->on_done_recv(op->recv_user_data, 1);
|
||||
}
|
||||
if (op->on_consumed) {
|
||||
op->on_consumed(op->on_consumed_user_data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void channel_op(grpc_channel_element *elem,
|
||||
|
|
@ -115,9 +118,9 @@ static void init_channel_elem(grpc_channel_element *elem,
|
|||
static void destroy_channel_elem(grpc_channel_element *elem) {}
|
||||
|
||||
static const grpc_channel_filter lame_filter = {
|
||||
lame_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
|
||||
destroy_call_elem, sizeof(channel_data), init_channel_elem,
|
||||
destroy_channel_elem, "lame-client",
|
||||
lame_start_transport_op, channel_op, sizeof(call_data),
|
||||
init_call_elem, destroy_call_elem, sizeof(channel_data),
|
||||
init_channel_elem, destroy_channel_elem, "lame-client",
|
||||
};
|
||||
|
||||
grpc_channel *grpc_lame_client_channel_create(void) {
|
||||
|
|
|
|||
|
|
@ -97,12 +97,13 @@ static void on_secure_transport_setup_done(void *rp,
|
|||
if (status != GRPC_SECURITY_OK) {
|
||||
gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
|
||||
done(r, 0);
|
||||
} else if (grpc_client_setup_cb_begin(r->cs_request)) {
|
||||
} else if (grpc_client_setup_cb_begin(r->cs_request,
|
||||
"on_secure_transport_setup_done")) {
|
||||
grpc_create_chttp2_transport(
|
||||
r->setup->setup_callback, r->setup->setup_user_data,
|
||||
grpc_client_setup_get_channel_args(r->cs_request), secure_endpoint,
|
||||
NULL, 0, grpc_client_setup_get_mdctx(r->cs_request), 1);
|
||||
grpc_client_setup_cb_end(r->cs_request);
|
||||
grpc_client_setup_cb_end(r->cs_request, "on_secure_transport_setup_done");
|
||||
done(r, 1);
|
||||
} else {
|
||||
done(r, 0);
|
||||
|
|
@ -113,7 +114,8 @@ static void on_secure_transport_setup_done(void *rp,
|
|||
static void on_connect(void *rp, grpc_endpoint *tcp) {
|
||||
request *r = rp;
|
||||
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request)) {
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request,
|
||||
"on_connect.secure")) {
|
||||
if (tcp) {
|
||||
grpc_endpoint_shutdown(tcp);
|
||||
grpc_endpoint_destroy(tcp);
|
||||
|
|
@ -141,9 +143,10 @@ static int maybe_try_next_resolved(request *r) {
|
|||
if (!r->resolved) return 0;
|
||||
if (r->resolved_index == r->resolved->naddrs) return 0;
|
||||
addr = &r->resolved->addrs[r->resolved_index++];
|
||||
grpc_tcp_client_connect(on_connect, r, (struct sockaddr *)&addr->addr,
|
||||
addr->len,
|
||||
grpc_client_setup_request_deadline(r->cs_request));
|
||||
grpc_tcp_client_connect(
|
||||
on_connect, r, grpc_client_setup_get_interested_parties(r->cs_request),
|
||||
(struct sockaddr *)&addr->addr, addr->len,
|
||||
grpc_client_setup_request_deadline(r->cs_request));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +155,8 @@ static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
|
|||
request *r = rp;
|
||||
|
||||
/* if we're not still the active request, abort */
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request)) {
|
||||
if (!grpc_client_setup_request_should_continue(r->cs_request,
|
||||
"on_resolved.secure")) {
|
||||
if (resolved) {
|
||||
grpc_resolved_addresses_destroy(resolved);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ typedef struct channel_registered_method {
|
|||
|
||||
struct channel_data {
|
||||
grpc_server *server;
|
||||
size_t num_calls;
|
||||
grpc_channel *channel;
|
||||
grpc_mdstr *path_key;
|
||||
grpc_mdstr *authority_key;
|
||||
|
|
@ -123,10 +124,14 @@ struct channel_data {
|
|||
channel_registered_method *registered_methods;
|
||||
gpr_uint32 registered_method_slots;
|
||||
gpr_uint32 registered_method_max_probes;
|
||||
grpc_iomgr_closure finish_shutdown_channel_closure;
|
||||
grpc_iomgr_closure finish_destroy_channel_closure;
|
||||
};
|
||||
|
||||
typedef struct shutdown_tag {
|
||||
void *tag;
|
||||
grpc_completion_queue *cq;
|
||||
} shutdown_tag;
|
||||
|
||||
struct grpc_server {
|
||||
size_t channel_filter_count;
|
||||
const grpc_channel_filter **channel_filters;
|
||||
|
|
@ -136,15 +141,23 @@ struct grpc_server {
|
|||
grpc_pollset **pollsets;
|
||||
size_t cq_count;
|
||||
|
||||
gpr_mu mu;
|
||||
gpr_cv cv;
|
||||
/* The two following mutexes control access to server-state
|
||||
mu_global controls access to non-call-related state (e.g., channel state)
|
||||
mu_call controls access to call-related state (e.g., the call lists)
|
||||
|
||||
If they are ever required to be nested, you must lock mu_global
|
||||
before mu_call. This is currently used in shutdown processing
|
||||
(grpc_server_shutdown_and_notify and maybe_finish_shutdown) */
|
||||
gpr_mu mu_global; /* mutex for server and channel state */
|
||||
gpr_mu mu_call; /* mutex for call-specific state */
|
||||
|
||||
registered_method *registered_methods;
|
||||
requested_call_array requested_calls;
|
||||
|
||||
gpr_uint8 shutdown;
|
||||
gpr_uint8 shutdown_published;
|
||||
size_t num_shutdown_tags;
|
||||
void **shutdown_tags;
|
||||
shutdown_tag *shutdown_tags;
|
||||
|
||||
call_data *lists[CALL_LIST_COUNT];
|
||||
channel_data root_channel_data;
|
||||
|
|
@ -193,6 +206,11 @@ struct call_data {
|
|||
static void begin_call(grpc_server *server, call_data *calld,
|
||||
requested_call *rc);
|
||||
static void fail_call(grpc_server *server, requested_call *rc);
|
||||
static void shutdown_channel(channel_data *chand, int send_goaway,
|
||||
int send_disconnect);
|
||||
/* Before calling maybe_finish_shutdown, we must hold mu_global and not
|
||||
hold mu_call */
|
||||
static void maybe_finish_shutdown(grpc_server *server);
|
||||
|
||||
static int call_list_join(call_data **root, call_data *call, call_list list) {
|
||||
GPR_ASSERT(!call->root[list]);
|
||||
|
|
@ -261,29 +279,33 @@ static void server_ref(grpc_server *server) {
|
|||
gpr_ref(&server->internal_refcount);
|
||||
}
|
||||
|
||||
static void server_unref(grpc_server *server) {
|
||||
static void server_delete(grpc_server *server) {
|
||||
registered_method *rm;
|
||||
size_t i;
|
||||
grpc_channel_args_destroy(server->channel_args);
|
||||
gpr_mu_destroy(&server->mu_global);
|
||||
gpr_mu_destroy(&server->mu_call);
|
||||
gpr_free(server->channel_filters);
|
||||
requested_call_array_destroy(&server->requested_calls);
|
||||
while ((rm = server->registered_methods) != NULL) {
|
||||
server->registered_methods = rm->next;
|
||||
gpr_free(rm->method);
|
||||
gpr_free(rm->host);
|
||||
requested_call_array_destroy(&rm->requested);
|
||||
gpr_free(rm);
|
||||
}
|
||||
for (i = 0; i < server->cq_count; i++) {
|
||||
GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server");
|
||||
}
|
||||
gpr_free(server->cqs);
|
||||
gpr_free(server->pollsets);
|
||||
gpr_free(server->shutdown_tags);
|
||||
gpr_free(server);
|
||||
}
|
||||
|
||||
static void server_unref(grpc_server *server) {
|
||||
if (gpr_unref(&server->internal_refcount)) {
|
||||
grpc_channel_args_destroy(server->channel_args);
|
||||
gpr_mu_destroy(&server->mu);
|
||||
gpr_cv_destroy(&server->cv);
|
||||
gpr_free(server->channel_filters);
|
||||
requested_call_array_destroy(&server->requested_calls);
|
||||
while ((rm = server->registered_methods) != NULL) {
|
||||
server->registered_methods = rm->next;
|
||||
gpr_free(rm->method);
|
||||
gpr_free(rm->host);
|
||||
requested_call_array_destroy(&rm->requested);
|
||||
gpr_free(rm);
|
||||
}
|
||||
for (i = 0; i < server->cq_count; i++) {
|
||||
grpc_cq_internal_unref(server->cqs[i]);
|
||||
}
|
||||
gpr_free(server->cqs);
|
||||
gpr_free(server->pollsets);
|
||||
gpr_free(server->shutdown_tags);
|
||||
gpr_free(server);
|
||||
server_delete(server);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +322,7 @@ static void orphan_channel(channel_data *chand) {
|
|||
static void finish_destroy_channel(void *cd, int success) {
|
||||
channel_data *chand = cd;
|
||||
grpc_server *server = chand->server;
|
||||
grpc_channel_internal_unref(chand->channel);
|
||||
GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server");
|
||||
server_unref(server);
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +331,7 @@ static void destroy_channel(channel_data *chand) {
|
|||
GPR_ASSERT(chand->server != NULL);
|
||||
orphan_channel(chand);
|
||||
server_ref(chand->server);
|
||||
maybe_finish_shutdown(chand->server);
|
||||
chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
|
||||
chand->finish_destroy_channel_closure.cb_arg = chand;
|
||||
grpc_iomgr_add_callback(&chand->finish_destroy_channel_closure);
|
||||
|
|
@ -323,11 +346,11 @@ static void finish_start_new_rpc_and_unlock(grpc_server *server,
|
|||
if (array->count == 0) {
|
||||
calld->state = PENDING;
|
||||
call_list_join(pending_root, calld, PENDING_START);
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
} else {
|
||||
rc = array->calls[--array->count];
|
||||
calld->state = ACTIVATED;
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
begin_call(server, calld, &rc);
|
||||
}
|
||||
}
|
||||
|
|
@ -340,7 +363,7 @@ static void start_new_rpc(grpc_call_element *elem) {
|
|||
gpr_uint32 hash;
|
||||
channel_registered_method *rm;
|
||||
|
||||
gpr_mu_lock(&server->mu);
|
||||
gpr_mu_lock(&server->mu_call);
|
||||
if (chand->registered_methods && calld->path && calld->host) {
|
||||
/* TODO(ctiller): unify these two searches */
|
||||
/* check for an exact match with host */
|
||||
|
|
@ -378,6 +401,47 @@ static void kill_zombie(void *elem, int success) {
|
|||
grpc_call_destroy(grpc_call_from_top_element(elem));
|
||||
}
|
||||
|
||||
static int num_listeners(grpc_server *server) {
|
||||
listener *l;
|
||||
int n = 0;
|
||||
for (l = server->listeners; l; l = l->next) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void maybe_finish_shutdown(grpc_server *server) {
|
||||
size_t i;
|
||||
if (!server->shutdown || server->shutdown_published) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpr_mu_lock(&server->mu_call);
|
||||
if (server->lists[ALL_CALLS] != NULL) {
|
||||
gpr_log(GPR_DEBUG,
|
||||
"Waiting for all calls to finish before destroying server");
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
return;
|
||||
}
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
|
||||
if (server->root_channel_data.next != &server->root_channel_data) {
|
||||
gpr_log(GPR_DEBUG,
|
||||
"Waiting for all channels to close before destroying server");
|
||||
return;
|
||||
}
|
||||
if (server->listeners_destroyed < num_listeners(server)) {
|
||||
gpr_log(GPR_DEBUG, "Waiting for all listeners to be destroyed (@ %d/%d)",
|
||||
server->listeners_destroyed, num_listeners(server));
|
||||
return;
|
||||
}
|
||||
server->shutdown_published = 1;
|
||||
for (i = 0; i < server->num_shutdown_tags; i++) {
|
||||
grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag,
|
||||
NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
|
||||
grpc_call_element *elem = user_data;
|
||||
channel_data *chand = elem->channel_data;
|
||||
|
|
@ -392,10 +456,19 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
|
|||
return md;
|
||||
}
|
||||
|
||||
static void decrement_call_count(channel_data *chand) {
|
||||
chand->num_calls--;
|
||||
if (0 == chand->num_calls && chand->server->shutdown) {
|
||||
shutdown_channel(chand, 0, 1);
|
||||
}
|
||||
maybe_finish_shutdown(chand->server);
|
||||
}
|
||||
|
||||
static void server_on_recv(void *ptr, int success) {
|
||||
grpc_call_element *elem = ptr;
|
||||
call_data *calld = elem->call_data;
|
||||
channel_data *chand = elem->channel_data;
|
||||
int remove_res;
|
||||
|
||||
if (success && !calld->got_initial_metadata) {
|
||||
size_t i;
|
||||
|
|
@ -420,16 +493,16 @@ static void server_on_recv(void *ptr, int success) {
|
|||
case GRPC_STREAM_SEND_CLOSED:
|
||||
break;
|
||||
case GRPC_STREAM_RECV_CLOSED:
|
||||
gpr_mu_lock(&chand->server->mu);
|
||||
gpr_mu_lock(&chand->server->mu_call);
|
||||
if (calld->state == NOT_STARTED) {
|
||||
calld->state = ZOMBIED;
|
||||
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
|
||||
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
|
||||
}
|
||||
gpr_mu_unlock(&chand->server->mu);
|
||||
gpr_mu_unlock(&chand->server->mu_call);
|
||||
break;
|
||||
case GRPC_STREAM_CLOSED:
|
||||
gpr_mu_lock(&chand->server->mu);
|
||||
gpr_mu_lock(&chand->server->mu_call);
|
||||
if (calld->state == NOT_STARTED) {
|
||||
calld->state = ZOMBIED;
|
||||
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
|
||||
|
|
@ -439,9 +512,14 @@ static void server_on_recv(void *ptr, int success) {
|
|||
calld->state = ZOMBIED;
|
||||
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
|
||||
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
|
||||
|
||||
}
|
||||
gpr_mu_unlock(&chand->server->mu);
|
||||
remove_res = call_list_remove(calld, ALL_CALLS);
|
||||
gpr_mu_unlock(&chand->server->mu_call);
|
||||
gpr_mu_lock(&chand->server->mu_global);
|
||||
if (remove_res) {
|
||||
decrement_call_count(chand);
|
||||
}
|
||||
gpr_mu_unlock(&chand->server->mu_global);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -484,10 +562,10 @@ static void channel_op(grpc_channel_element *elem,
|
|||
case GRPC_TRANSPORT_CLOSED:
|
||||
/* if the transport is closed for a server channel, we destroy the
|
||||
channel */
|
||||
gpr_mu_lock(&server->mu);
|
||||
gpr_mu_lock(&server->mu_global);
|
||||
server_ref(server);
|
||||
destroy_channel(chand);
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_global);
|
||||
server_unref(server);
|
||||
break;
|
||||
case GRPC_TRANSPORT_GOAWAY:
|
||||
|
|
@ -500,22 +578,49 @@ static void channel_op(grpc_channel_element *elem,
|
|||
}
|
||||
}
|
||||
|
||||
static void finish_shutdown_channel(void *cd, int success) {
|
||||
channel_data *chand = cd;
|
||||
typedef struct {
|
||||
channel_data *chand;
|
||||
int send_goaway;
|
||||
int send_disconnect;
|
||||
grpc_iomgr_closure finish_shutdown_channel_closure;
|
||||
} shutdown_channel_args;
|
||||
|
||||
static void finish_shutdown_channel(void *p, int success) {
|
||||
shutdown_channel_args *sca = p;
|
||||
grpc_channel_op op;
|
||||
op.type = GRPC_CHANNEL_DISCONNECT;
|
||||
op.dir = GRPC_CALL_DOWN;
|
||||
channel_op(grpc_channel_stack_element(
|
||||
grpc_channel_get_channel_stack(chand->channel), 0),
|
||||
NULL, &op);
|
||||
grpc_channel_internal_unref(chand->channel);
|
||||
|
||||
if (sca->send_goaway) {
|
||||
op.type = GRPC_CHANNEL_GOAWAY;
|
||||
op.dir = GRPC_CALL_DOWN;
|
||||
op.data.goaway.status = GRPC_STATUS_OK;
|
||||
op.data.goaway.message = gpr_slice_from_copied_string("Server shutdown");
|
||||
channel_op(grpc_channel_stack_element(
|
||||
grpc_channel_get_channel_stack(sca->chand->channel), 0),
|
||||
NULL, &op);
|
||||
}
|
||||
if (sca->send_disconnect) {
|
||||
op.type = GRPC_CHANNEL_DISCONNECT;
|
||||
op.dir = GRPC_CALL_DOWN;
|
||||
channel_op(grpc_channel_stack_element(
|
||||
grpc_channel_get_channel_stack(sca->chand->channel), 0),
|
||||
NULL, &op);
|
||||
}
|
||||
GRPC_CHANNEL_INTERNAL_UNREF(sca->chand->channel, "shutdown");
|
||||
|
||||
gpr_free(sca);
|
||||
}
|
||||
|
||||
static void shutdown_channel(channel_data *chand) {
|
||||
grpc_channel_internal_ref(chand->channel);
|
||||
chand->finish_shutdown_channel_closure.cb = finish_shutdown_channel;
|
||||
chand->finish_shutdown_channel_closure.cb_arg = chand;
|
||||
grpc_iomgr_add_callback(&chand->finish_shutdown_channel_closure);
|
||||
static void shutdown_channel(channel_data *chand, int send_goaway,
|
||||
int send_disconnect) {
|
||||
shutdown_channel_args *sca;
|
||||
GRPC_CHANNEL_INTERNAL_REF(chand->channel, "shutdown");
|
||||
sca = gpr_malloc(sizeof(shutdown_channel_args));
|
||||
sca->chand = chand;
|
||||
sca->send_goaway = send_goaway;
|
||||
sca->send_disconnect = send_disconnect;
|
||||
sca->finish_shutdown_channel_closure.cb = finish_shutdown_channel;
|
||||
sca->finish_shutdown_channel_closure.cb_arg = sca;
|
||||
grpc_iomgr_add_callback(&sca->finish_shutdown_channel_closure);
|
||||
}
|
||||
|
||||
static void init_call_elem(grpc_call_element *elem,
|
||||
|
|
@ -527,9 +632,13 @@ static void init_call_elem(grpc_call_element *elem,
|
|||
calld->deadline = gpr_inf_future;
|
||||
calld->call = grpc_call_from_top_element(elem);
|
||||
|
||||
gpr_mu_lock(&chand->server->mu);
|
||||
gpr_mu_lock(&chand->server->mu_call);
|
||||
call_list_join(&chand->server->lists[ALL_CALLS], calld, ALL_CALLS);
|
||||
gpr_mu_unlock(&chand->server->mu);
|
||||
gpr_mu_unlock(&chand->server->mu_call);
|
||||
|
||||
gpr_mu_lock(&chand->server->mu_global);
|
||||
chand->num_calls++;
|
||||
gpr_mu_unlock(&chand->server->mu_global);
|
||||
|
||||
server_ref(chand->server);
|
||||
|
||||
|
|
@ -539,21 +648,19 @@ static void init_call_elem(grpc_call_element *elem,
|
|||
static void destroy_call_elem(grpc_call_element *elem) {
|
||||
channel_data *chand = elem->channel_data;
|
||||
call_data *calld = elem->call_data;
|
||||
size_t i, j;
|
||||
int removed[CALL_LIST_COUNT];
|
||||
size_t i;
|
||||
|
||||
gpr_mu_lock(&chand->server->mu);
|
||||
gpr_mu_lock(&chand->server->mu_call);
|
||||
for (i = 0; i < CALL_LIST_COUNT; i++) {
|
||||
call_list_remove(elem->call_data, i);
|
||||
removed[i] = call_list_remove(elem->call_data, i);
|
||||
}
|
||||
if (chand->server->shutdown && chand->server->lists[ALL_CALLS] == NULL) {
|
||||
for (i = 0; i < chand->server->num_shutdown_tags; i++) {
|
||||
for (j = 0; j < chand->server->cq_count; j++) {
|
||||
grpc_cq_end_op(chand->server->cqs[j], chand->server->shutdown_tags[i],
|
||||
NULL, 1);
|
||||
}
|
||||
}
|
||||
gpr_mu_unlock(&chand->server->mu_call);
|
||||
if (removed[ALL_CALLS]) {
|
||||
gpr_mu_lock(&chand->server->mu_global);
|
||||
decrement_call_count(chand);
|
||||
gpr_mu_unlock(&chand->server->mu_global);
|
||||
}
|
||||
gpr_mu_unlock(&chand->server->mu);
|
||||
|
||||
if (calld->host) {
|
||||
grpc_mdstr_unref(calld->host);
|
||||
|
|
@ -573,6 +680,7 @@ static void init_channel_elem(grpc_channel_element *elem,
|
|||
GPR_ASSERT(is_first);
|
||||
GPR_ASSERT(!is_last);
|
||||
chand->server = NULL;
|
||||
chand->num_calls = 0;
|
||||
chand->channel = NULL;
|
||||
chand->path_key = grpc_mdstr_from_string(metadata_context, ":path");
|
||||
chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
|
||||
|
|
@ -595,11 +703,12 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
|
|||
gpr_free(chand->registered_methods);
|
||||
}
|
||||
if (chand->server) {
|
||||
gpr_mu_lock(&chand->server->mu);
|
||||
gpr_mu_lock(&chand->server->mu_global);
|
||||
chand->next->prev = chand->prev;
|
||||
chand->prev->next = chand->next;
|
||||
chand->next = chand->prev = chand;
|
||||
gpr_mu_unlock(&chand->server->mu);
|
||||
maybe_finish_shutdown(chand->server);
|
||||
gpr_mu_unlock(&chand->server->mu_global);
|
||||
grpc_mdstr_unref(chand->path_key);
|
||||
grpc_mdstr_unref(chand->authority_key);
|
||||
server_unref(chand->server);
|
||||
|
|
@ -624,7 +733,8 @@ void grpc_server_register_completion_queue(grpc_server *server,
|
|||
for (i = 0; i < server->cq_count; i++) {
|
||||
if (server->cqs[i] == cq) return;
|
||||
}
|
||||
grpc_cq_internal_ref(cq);
|
||||
GRPC_CQ_INTERNAL_REF(cq, "server");
|
||||
grpc_cq_mark_server_cq(cq);
|
||||
n = server->cq_count++;
|
||||
server->cqs = gpr_realloc(server->cqs,
|
||||
server->cq_count * sizeof(grpc_completion_queue *));
|
||||
|
|
@ -645,8 +755,8 @@ grpc_server *grpc_server_create_from_filters(grpc_channel_filter **filters,
|
|||
|
||||
memset(server, 0, sizeof(grpc_server));
|
||||
|
||||
gpr_mu_init(&server->mu);
|
||||
gpr_cv_init(&server->cv);
|
||||
gpr_mu_init(&server->mu_global);
|
||||
gpr_mu_init(&server->mu_call);
|
||||
|
||||
/* decremented by grpc_server_destroy */
|
||||
gpr_ref_init(&server->internal_refcount, 1);
|
||||
|
|
@ -687,7 +797,8 @@ void *grpc_server_register_method(grpc_server *server, const char *method,
|
|||
const char *host) {
|
||||
registered_method *m;
|
||||
if (!method) {
|
||||
gpr_log(GPR_ERROR, "grpc_server_register_method method string cannot be NULL");
|
||||
gpr_log(GPR_ERROR,
|
||||
"grpc_server_register_method method string cannot be NULL");
|
||||
return NULL;
|
||||
}
|
||||
for (m = server->registered_methods; m; m = m->next) {
|
||||
|
|
@ -795,69 +906,47 @@ grpc_transport_setup_result grpc_server_setup_transport(
|
|||
result = grpc_connected_channel_bind_transport(
|
||||
grpc_channel_get_channel_stack(channel), transport);
|
||||
|
||||
gpr_mu_lock(&s->mu);
|
||||
gpr_mu_lock(&s->mu_global);
|
||||
chand->next = &s->root_channel_data;
|
||||
chand->prev = chand->next->prev;
|
||||
chand->next->prev = chand->prev->next = chand;
|
||||
gpr_mu_unlock(&s->mu);
|
||||
gpr_mu_unlock(&s->mu_global);
|
||||
|
||||
gpr_free(filters);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int num_listeners(grpc_server *server) {
|
||||
listener *l;
|
||||
int n = 0;
|
||||
for (l = server->listeners; l; l = l->next) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
|
||||
void *shutdown_tag) {
|
||||
void grpc_server_shutdown_and_notify(grpc_server *server,
|
||||
grpc_completion_queue *cq, void *tag) {
|
||||
listener *l;
|
||||
requested_call_array requested_calls;
|
||||
channel_data **channels;
|
||||
channel_data *c;
|
||||
size_t nchannels;
|
||||
size_t i, j;
|
||||
grpc_channel_op op;
|
||||
grpc_channel_element *elem;
|
||||
size_t i;
|
||||
registered_method *rm;
|
||||
shutdown_tag *sdt;
|
||||
|
||||
/* lock, and gather up some stuff to do */
|
||||
gpr_mu_lock(&server->mu);
|
||||
if (have_shutdown_tag) {
|
||||
for (i = 0; i < server->cq_count; i++) {
|
||||
grpc_cq_begin_op(server->cqs[i], NULL);
|
||||
}
|
||||
server->shutdown_tags =
|
||||
gpr_realloc(server->shutdown_tags,
|
||||
sizeof(void *) * (server->num_shutdown_tags + 1));
|
||||
server->shutdown_tags[server->num_shutdown_tags++] = shutdown_tag;
|
||||
}
|
||||
gpr_mu_lock(&server->mu_global);
|
||||
grpc_cq_begin_op(cq, NULL);
|
||||
server->shutdown_tags =
|
||||
gpr_realloc(server->shutdown_tags,
|
||||
sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
|
||||
sdt = &server->shutdown_tags[server->num_shutdown_tags++];
|
||||
sdt->tag = tag;
|
||||
sdt->cq = cq;
|
||||
if (server->shutdown) {
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_global);
|
||||
return;
|
||||
}
|
||||
|
||||
nchannels = 0;
|
||||
for (c = server->root_channel_data.next; c != &server->root_channel_data;
|
||||
c = c->next) {
|
||||
nchannels++;
|
||||
}
|
||||
channels = gpr_malloc(sizeof(channel_data *) * nchannels);
|
||||
i = 0;
|
||||
for (c = server->root_channel_data.next; c != &server->root_channel_data;
|
||||
c = c->next) {
|
||||
grpc_channel_internal_ref(c->channel);
|
||||
channels[i] = c;
|
||||
i++;
|
||||
shutdown_channel(c, 1, c->num_calls == 0);
|
||||
}
|
||||
|
||||
/* collect all unregistered then registered calls */
|
||||
gpr_mu_lock(&server->mu_call);
|
||||
requested_calls = server->requested_calls;
|
||||
memset(&server->requested_calls, 0, sizeof(server->requested_calls));
|
||||
for (rm = server->registered_methods; rm; rm = rm->next) {
|
||||
|
|
@ -876,31 +965,11 @@ static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
|
|||
gpr_free(rm->requested.calls);
|
||||
memset(&rm->requested, 0, sizeof(rm->requested));
|
||||
}
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
|
||||
server->shutdown = 1;
|
||||
if (server->lists[ALL_CALLS] == NULL) {
|
||||
for (i = 0; i < server->num_shutdown_tags; i++) {
|
||||
for (j = 0; j < server->cq_count; j++) {
|
||||
grpc_cq_end_op(server->cqs[j], server->shutdown_tags[i], NULL, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
gpr_mu_unlock(&server->mu);
|
||||
|
||||
for (i = 0; i < nchannels; i++) {
|
||||
c = channels[i];
|
||||
elem = grpc_channel_stack_element(
|
||||
grpc_channel_get_channel_stack(c->channel), 0);
|
||||
|
||||
op.type = GRPC_CHANNEL_GOAWAY;
|
||||
op.dir = GRPC_CALL_DOWN;
|
||||
op.data.goaway.status = GRPC_STATUS_OK;
|
||||
op.data.goaway.message = gpr_slice_from_copied_string("Server shutdown");
|
||||
elem->filter->channel_op(elem, NULL, &op);
|
||||
|
||||
grpc_channel_internal_unref(c->channel);
|
||||
}
|
||||
gpr_free(channels);
|
||||
maybe_finish_shutdown(server);
|
||||
gpr_mu_unlock(&server->mu_global);
|
||||
|
||||
/* terminate all the requested calls */
|
||||
for (i = 0; i < requested_calls.count; i++) {
|
||||
|
|
@ -914,45 +983,64 @@ static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
|
|||
}
|
||||
}
|
||||
|
||||
void grpc_server_shutdown(grpc_server *server) {
|
||||
shutdown_internal(server, 0, NULL);
|
||||
}
|
||||
|
||||
void grpc_server_shutdown_and_notify(grpc_server *server, void *tag) {
|
||||
shutdown_internal(server, 1, tag);
|
||||
}
|
||||
|
||||
void grpc_server_listener_destroy_done(void *s) {
|
||||
grpc_server *server = s;
|
||||
gpr_mu_lock(&server->mu);
|
||||
gpr_mu_lock(&server->mu_global);
|
||||
server->listeners_destroyed++;
|
||||
gpr_cv_signal(&server->cv);
|
||||
gpr_mu_unlock(&server->mu);
|
||||
maybe_finish_shutdown(server);
|
||||
gpr_mu_unlock(&server->mu_global);
|
||||
}
|
||||
|
||||
void grpc_server_cancel_all_calls(grpc_server *server) {
|
||||
call_data *calld;
|
||||
grpc_call **calls;
|
||||
size_t call_count;
|
||||
size_t call_capacity;
|
||||
int is_first = 1;
|
||||
size_t i;
|
||||
|
||||
gpr_mu_lock(&server->mu_call);
|
||||
|
||||
GPR_ASSERT(server->shutdown);
|
||||
|
||||
if (!server->lists[ALL_CALLS]) {
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
return;
|
||||
}
|
||||
|
||||
call_capacity = 8;
|
||||
call_count = 0;
|
||||
calls = gpr_malloc(sizeof(grpc_call *) * call_capacity);
|
||||
|
||||
for (calld = server->lists[ALL_CALLS];
|
||||
calld != server->lists[ALL_CALLS] || is_first;
|
||||
calld = calld->links[ALL_CALLS].next) {
|
||||
if (call_count == call_capacity) {
|
||||
call_capacity *= 2;
|
||||
calls = gpr_realloc(calls, sizeof(grpc_call *) * call_capacity);
|
||||
}
|
||||
calls[call_count++] = calld->call;
|
||||
GRPC_CALL_INTERNAL_REF(calld->call, "cancel_all");
|
||||
is_first = 0;
|
||||
}
|
||||
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
|
||||
for (i = 0; i < call_count; i++) {
|
||||
grpc_call_cancel_with_status(calls[i], GRPC_STATUS_UNAVAILABLE,
|
||||
"Unavailable");
|
||||
GRPC_CALL_INTERNAL_UNREF(calls[i], "cancel_all", 1);
|
||||
}
|
||||
|
||||
gpr_free(calls);
|
||||
}
|
||||
|
||||
void grpc_server_destroy(grpc_server *server) {
|
||||
channel_data *c;
|
||||
listener *l;
|
||||
size_t i;
|
||||
call_data *calld;
|
||||
|
||||
gpr_mu_lock(&server->mu);
|
||||
if (!server->shutdown) {
|
||||
gpr_mu_unlock(&server->mu);
|
||||
grpc_server_shutdown(server);
|
||||
gpr_mu_lock(&server->mu);
|
||||
}
|
||||
|
||||
while (server->listeners_destroyed != num_listeners(server)) {
|
||||
for (i = 0; i < server->cq_count; i++) {
|
||||
gpr_mu_unlock(&server->mu);
|
||||
grpc_cq_hack_spin_pollset(server->cqs[i]);
|
||||
gpr_mu_lock(&server->mu);
|
||||
}
|
||||
|
||||
gpr_cv_wait(&server->cv, &server->mu,
|
||||
gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
|
||||
}
|
||||
gpr_mu_lock(&server->mu_global);
|
||||
GPR_ASSERT(server->shutdown || !server->listeners);
|
||||
GPR_ASSERT(server->listeners_destroyed == num_listeners(server));
|
||||
|
||||
while (server->listeners) {
|
||||
l = server->listeners;
|
||||
|
|
@ -960,24 +1048,7 @@ void grpc_server_destroy(grpc_server *server) {
|
|||
gpr_free(l);
|
||||
}
|
||||
|
||||
while ((calld = call_list_remove_head(&server->lists[PENDING_START],
|
||||
PENDING_START)) != NULL) {
|
||||
/* TODO(dgq): If we knew the size of the call list (or an upper bound), we
|
||||
* could allocate all the memory for the closures in advance in a single
|
||||
* chunk */
|
||||
gpr_log(GPR_DEBUG, "server destroys call %p", calld->call);
|
||||
calld->state = ZOMBIED;
|
||||
grpc_iomgr_closure_init(
|
||||
&calld->kill_zombie_closure, kill_zombie,
|
||||
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
|
||||
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
|
||||
}
|
||||
|
||||
for (c = server->root_channel_data.next; c != &server->root_channel_data;
|
||||
c = c->next) {
|
||||
shutdown_channel(c);
|
||||
}
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_global);
|
||||
|
||||
server_unref(server);
|
||||
}
|
||||
|
|
@ -999,9 +1070,9 @@ static grpc_call_error queue_call_request(grpc_server *server,
|
|||
requested_call *rc) {
|
||||
call_data *calld = NULL;
|
||||
requested_call_array *requested_calls = NULL;
|
||||
gpr_mu_lock(&server->mu);
|
||||
gpr_mu_lock(&server->mu_call);
|
||||
if (server->shutdown) {
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
fail_call(server, rc);
|
||||
return GRPC_CALL_OK;
|
||||
}
|
||||
|
|
@ -1020,12 +1091,12 @@ static grpc_call_error queue_call_request(grpc_server *server,
|
|||
if (calld) {
|
||||
GPR_ASSERT(calld->state == PENDING);
|
||||
calld->state = ACTIVATED;
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
begin_call(server, calld, rc);
|
||||
return GRPC_CALL_OK;
|
||||
} else {
|
||||
*requested_call_array_add(requested_calls) = *rc;
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_call);
|
||||
return GRPC_CALL_OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -1039,6 +1110,9 @@ grpc_call_error grpc_server_request_call(
|
|||
GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details,
|
||||
initial_metadata, cq_bound_to_call,
|
||||
cq_for_notification, tag);
|
||||
if (!grpc_cq_is_server_cq(cq_for_notification)) {
|
||||
return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
|
||||
}
|
||||
grpc_cq_begin_op(cq_for_notification, NULL);
|
||||
rc.type = BATCH_CALL;
|
||||
rc.tag = tag;
|
||||
|
|
@ -1057,6 +1131,9 @@ grpc_call_error grpc_server_request_registered_call(
|
|||
grpc_completion_queue *cq_for_notification, void *tag) {
|
||||
requested_call rc;
|
||||
registered_method *registered_method = rm;
|
||||
if (!grpc_cq_is_server_cq(cq_for_notification)) {
|
||||
return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
|
||||
}
|
||||
grpc_cq_begin_op(cq_for_notification, NULL);
|
||||
rc.type = REGISTERED_CALL;
|
||||
rc.tag = tag;
|
||||
|
|
@ -1111,6 +1188,7 @@ static void begin_call(grpc_server *server, call_data *calld,
|
|||
rc->data.batch.details->deadline = calld->deadline;
|
||||
r->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
|
||||
r->data.recv_metadata = rc->data.batch.initial_metadata;
|
||||
r->flags = 0;
|
||||
r++;
|
||||
publish = publish_registered_or_batch;
|
||||
break;
|
||||
|
|
@ -1118,10 +1196,12 @@ static void begin_call(grpc_server *server, call_data *calld,
|
|||
*rc->data.registered.deadline = calld->deadline;
|
||||
r->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
|
||||
r->data.recv_metadata = rc->data.registered.initial_metadata;
|
||||
r->flags = 0;
|
||||
r++;
|
||||
if (rc->data.registered.optional_payload) {
|
||||
r->op = GRPC_IOREQ_RECV_MESSAGE;
|
||||
r->data.recv_message = rc->data.registered.optional_payload;
|
||||
r->flags = 0;
|
||||
r++;
|
||||
}
|
||||
publish = publish_registered_or_batch;
|
||||
|
|
@ -1160,9 +1240,8 @@ const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
|
|||
|
||||
int grpc_server_has_open_connections(grpc_server *server) {
|
||||
int r;
|
||||
gpr_mu_lock(&server->mu);
|
||||
gpr_mu_lock(&server->mu_global);
|
||||
r = server->root_channel_data.next != &server->root_channel_data;
|
||||
gpr_mu_unlock(&server->mu);
|
||||
gpr_mu_unlock(&server->mu_global);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -617,14 +617,19 @@ static void destroy_transport(grpc_transport *gt) {
|
|||
unref_transport(t);
|
||||
}
|
||||
|
||||
static void close_transport_locked(transport *t) {
|
||||
if (!t->closed) {
|
||||
t->closed = 1;
|
||||
if (t->ep) {
|
||||
grpc_endpoint_shutdown(t->ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void close_transport(grpc_transport *gt) {
|
||||
transport *t = (transport *)gt;
|
||||
gpr_mu_lock(&t->mu);
|
||||
GPR_ASSERT(!t->closed);
|
||||
t->closed = 1;
|
||||
if (t->ep) {
|
||||
grpc_endpoint_shutdown(t->ep);
|
||||
}
|
||||
close_transport_locked(t);
|
||||
gpr_mu_unlock(&t->mu);
|
||||
}
|
||||
|
||||
|
|
@ -1001,10 +1006,12 @@ static void finalize_outbuf(transport *t) {
|
|||
|
||||
while ((s = stream_list_remove_head(t, WRITING))) {
|
||||
grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops,
|
||||
s->send_closed != DONT_SEND_CLOSED, s->id, &t->hpack_compressor, &t->outbuf);
|
||||
s->send_closed != DONT_SEND_CLOSED, s->id,
|
||||
&t->hpack_compressor, &t->outbuf);
|
||||
s->writing_sopb.nops = 0;
|
||||
if (s->send_closed == SEND_CLOSED_WITH_RST_STREAM) {
|
||||
gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR));
|
||||
gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(
|
||||
s->id, GRPC_CHTTP2_NO_ERROR));
|
||||
}
|
||||
if (s->send_closed != DONT_SEND_CLOSED) {
|
||||
stream_list_join(t, s, WRITTEN_CLOSED);
|
||||
|
|
@ -1067,12 +1074,12 @@ static void perform_write(transport *t, grpc_endpoint *ep) {
|
|||
}
|
||||
}
|
||||
|
||||
static void add_goaway(transport *t, gpr_uint32 goaway_error, gpr_slice goaway_text) {
|
||||
static void add_goaway(transport *t, gpr_uint32 goaway_error,
|
||||
gpr_slice goaway_text) {
|
||||
if (t->num_pending_goaways == t->cap_pending_goaways) {
|
||||
t->cap_pending_goaways = GPR_MAX(1, t->cap_pending_goaways * 2);
|
||||
t->pending_goaways =
|
||||
gpr_realloc(t->pending_goaways,
|
||||
sizeof(pending_goaway) * t->cap_pending_goaways);
|
||||
t->pending_goaways = gpr_realloc(
|
||||
t->pending_goaways, sizeof(pending_goaway) * t->cap_pending_goaways);
|
||||
}
|
||||
t->pending_goaways[t->num_pending_goaways].status =
|
||||
grpc_chttp2_http2_error_to_grpc_status(goaway_error);
|
||||
|
|
@ -1080,13 +1087,12 @@ static void add_goaway(transport *t, gpr_uint32 goaway_error, gpr_slice goaway_t
|
|||
t->num_pending_goaways++;
|
||||
}
|
||||
|
||||
|
||||
static void maybe_start_some_streams(transport *t) {
|
||||
/* start streams where we have free stream ids and free concurrency */
|
||||
while (
|
||||
t->next_stream_id <= MAX_CLIENT_STREAM_ID &&
|
||||
grpc_chttp2_stream_map_size(&t->stream_map) <
|
||||
t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) {
|
||||
while (t->next_stream_id <= MAX_CLIENT_STREAM_ID &&
|
||||
grpc_chttp2_stream_map_size(&t->stream_map) <
|
||||
t->settings[PEER_SETTINGS]
|
||||
[GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) {
|
||||
stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY);
|
||||
if (!s) return;
|
||||
|
||||
|
|
@ -1094,7 +1100,9 @@ static void maybe_start_some_streams(transport *t) {
|
|||
t->is_client ? "CLI" : "SVR", s, t->next_stream_id));
|
||||
|
||||
if (t->next_stream_id == MAX_CLIENT_STREAM_ID) {
|
||||
add_goaway(t, GRPC_CHTTP2_NO_ERROR, gpr_slice_from_copied_string("Exceeded sequence number limit"));
|
||||
add_goaway(
|
||||
t, GRPC_CHTTP2_NO_ERROR,
|
||||
gpr_slice_from_copied_string("Exceeded sequence number limit"));
|
||||
}
|
||||
|
||||
GPR_ASSERT(s->id == 0);
|
||||
|
|
@ -1112,7 +1120,10 @@ static void maybe_start_some_streams(transport *t) {
|
|||
stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY);
|
||||
if (!s) return;
|
||||
|
||||
cancel_stream(t, s, GRPC_STATUS_UNAVAILABLE, grpc_chttp2_grpc_status_to_http2_error(GRPC_STATUS_UNAVAILABLE), NULL, 0);
|
||||
cancel_stream(
|
||||
t, s, GRPC_STATUS_UNAVAILABLE,
|
||||
grpc_chttp2_grpc_status_to_http2_error(GRPC_STATUS_UNAVAILABLE), NULL,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1165,6 +1176,13 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) {
|
|||
if (op->bind_pollset) {
|
||||
add_to_pollset_locked(t, op->bind_pollset);
|
||||
}
|
||||
|
||||
if (op->on_consumed) {
|
||||
op_closure c;
|
||||
c.cb = op->on_consumed;
|
||||
c.user_data = op->on_consumed_user_data;
|
||||
schedule_cb(t, c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void perform_op(grpc_transport *gt, grpc_stream *gs,
|
||||
|
|
@ -1258,8 +1276,8 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
|
|||
/* synthesize a status if we don't believe we'll get one */
|
||||
gpr_ltoa(local_status, buffer);
|
||||
add_incoming_metadata(
|
||||
t, s,
|
||||
grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer));
|
||||
t, s, grpc_mdelem_from_strings(t->metadata_context, "grpc-status",
|
||||
buffer));
|
||||
if (!optional_message) {
|
||||
switch (local_status) {
|
||||
case GRPC_STATUS_CANCELLED:
|
||||
|
|
@ -1321,6 +1339,7 @@ static void drop_connection(transport *t) {
|
|||
if (t->error_state == ERROR_STATE_NONE) {
|
||||
t->error_state = ERROR_STATE_SEEN;
|
||||
}
|
||||
close_transport_locked(t);
|
||||
end_all_the_calls(t);
|
||||
}
|
||||
|
||||
|
|
@ -1497,7 +1516,8 @@ static int init_header_frame_parser(transport *t, int is_continuation) {
|
|||
t->last_incoming_stream_id, t->incoming_stream_id);
|
||||
return init_skip_frame(t, 1);
|
||||
} else if ((t->incoming_stream_id & 1) == 0) {
|
||||
gpr_log(GPR_ERROR, "ignoring stream with non-client generated index %d", t->incoming_stream_id);
|
||||
gpr_log(GPR_ERROR, "ignoring stream with non-client generated index %d",
|
||||
t->incoming_stream_id);
|
||||
return init_skip_frame(t, 1);
|
||||
}
|
||||
t->incoming_stream = NULL;
|
||||
|
|
@ -1557,10 +1577,10 @@ static int init_ping_parser(transport *t) {
|
|||
}
|
||||
|
||||
static int init_rst_stream_parser(transport *t) {
|
||||
int ok = GRPC_CHTTP2_PARSE_OK ==
|
||||
grpc_chttp2_rst_stream_parser_begin_frame(&t->simple_parsers.rst_stream,
|
||||
t->incoming_frame_size,
|
||||
t->incoming_frame_flags);
|
||||
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame(
|
||||
&t->simple_parsers.rst_stream,
|
||||
t->incoming_frame_size,
|
||||
t->incoming_frame_flags);
|
||||
if (!ok) {
|
||||
drop_connection(t);
|
||||
}
|
||||
|
|
@ -1586,15 +1606,16 @@ static int init_settings_frame_parser(transport *t) {
|
|||
int ok;
|
||||
|
||||
if (t->incoming_stream_id != 0) {
|
||||
gpr_log(GPR_ERROR, "settings frame received for stream %d", t->incoming_stream_id);
|
||||
gpr_log(GPR_ERROR, "settings frame received for stream %d",
|
||||
t->incoming_stream_id);
|
||||
drop_connection(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = GRPC_CHTTP2_PARSE_OK ==
|
||||
grpc_chttp2_settings_parser_begin_frame(
|
||||
&t->simple_parsers.settings, t->incoming_frame_size,
|
||||
t->incoming_frame_flags, t->settings[PEER_SETTINGS]);
|
||||
grpc_chttp2_settings_parser_begin_frame(
|
||||
&t->simple_parsers.settings, t->incoming_frame_size,
|
||||
t->incoming_frame_flags, t->settings[PEER_SETTINGS]);
|
||||
if (!ok) {
|
||||
drop_connection(t);
|
||||
return 0;
|
||||
|
|
@ -1659,7 +1680,7 @@ static void add_metadata_batch(transport *t, stream *s) {
|
|||
we can reconstitute the list.
|
||||
We can't do list building here as later incoming metadata may reallocate
|
||||
the underlying array. */
|
||||
b.list.tail = (void*)(gpr_intptr)s->incoming_metadata_count;
|
||||
b.list.tail = (void *)(gpr_intptr)s->incoming_metadata_count;
|
||||
b.garbage.head = b.garbage.tail = NULL;
|
||||
b.deadline = s->incoming_deadline;
|
||||
s->incoming_deadline = gpr_inf_future;
|
||||
|
|
@ -2017,7 +2038,7 @@ static void patch_metadata_ops(stream *s) {
|
|||
int found_metadata = 0;
|
||||
|
||||
/* rework the array of metadata into a linked list, making use
|
||||
of the breadcrumbs we left in metadata batches during
|
||||
of the breadcrumbs we left in metadata batches during
|
||||
add_metadata_batch */
|
||||
for (i = 0; i < nops; i++) {
|
||||
grpc_stream_op *op = &ops[i];
|
||||
|
|
@ -2033,11 +2054,11 @@ static void patch_metadata_ops(stream *s) {
|
|||
op->data.metadata.list.head = &s->incoming_metadata[mdidx];
|
||||
op->data.metadata.list.tail = &s->incoming_metadata[last_mdidx - 1];
|
||||
for (j = mdidx + 1; j < last_mdidx; j++) {
|
||||
s->incoming_metadata[j].prev = &s->incoming_metadata[j-1];
|
||||
s->incoming_metadata[j-1].next = &s->incoming_metadata[j];
|
||||
s->incoming_metadata[j].prev = &s->incoming_metadata[j - 1];
|
||||
s->incoming_metadata[j - 1].next = &s->incoming_metadata[j];
|
||||
}
|
||||
s->incoming_metadata[mdidx].prev = NULL;
|
||||
s->incoming_metadata[last_mdidx-1].next = NULL;
|
||||
s->incoming_metadata[last_mdidx - 1].next = NULL;
|
||||
/* track where we're up to */
|
||||
mdidx = last_mdidx;
|
||||
}
|
||||
|
|
@ -2049,7 +2070,8 @@ static void patch_metadata_ops(stream *s) {
|
|||
size_t copy_bytes = sizeof(*s->incoming_metadata) * new_count;
|
||||
GPR_ASSERT(mdidx < s->incoming_metadata_count);
|
||||
s->incoming_metadata = gpr_malloc(copy_bytes);
|
||||
memcpy(s->old_incoming_metadata + mdidx, s->incoming_metadata, copy_bytes);
|
||||
memcpy(s->old_incoming_metadata + mdidx, s->incoming_metadata,
|
||||
copy_bytes);
|
||||
s->incoming_metadata_count = s->incoming_metadata_capacity = new_count;
|
||||
} else {
|
||||
s->incoming_metadata = NULL;
|
||||
|
|
@ -2086,7 +2108,6 @@ static void finish_reads(transport *t) {
|
|||
schedule_cb(t, s->recv_done_closure, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void schedule_cb(transport *t, op_closure closure, int success) {
|
||||
|
|
|
|||
|
|
@ -58,11 +58,18 @@ typedef enum grpc_stream_op_code {
|
|||
GRPC_OP_SLICE
|
||||
} grpc_stream_op_code;
|
||||
|
||||
/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
|
||||
* compression for the message */
|
||||
#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u)
|
||||
/** Mask of all valid internal flags. */
|
||||
#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
|
||||
|
||||
/* Arguments for GRPC_OP_BEGIN_MESSAGE */
|
||||
typedef struct grpc_begin_message {
|
||||
/* How many bytes of data will this message contain */
|
||||
gpr_uint32 length;
|
||||
/* Write flags for the message: see grpc.h GRPC_WRITE_xxx */
|
||||
/* Write flags for the message: see grpc.h GRPC_WRITE_* for the public bits,
|
||||
* GRPC_WRITE_INTERNAL_* for the internal ones. */
|
||||
gpr_uint32 flags;
|
||||
} grpc_begin_message;
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,16 @@ void grpc_transport_setup_initiate(grpc_transport_setup *setup) {
|
|||
setup->vtable->initiate(setup);
|
||||
}
|
||||
|
||||
void grpc_transport_setup_add_interested_party(grpc_transport_setup *setup,
|
||||
grpc_pollset *pollset) {
|
||||
setup->vtable->add_interested_party(setup, pollset);
|
||||
}
|
||||
|
||||
void grpc_transport_setup_del_interested_party(grpc_transport_setup *setup,
|
||||
grpc_pollset *pollset) {
|
||||
setup->vtable->del_interested_party(setup, pollset);
|
||||
}
|
||||
|
||||
void grpc_transport_op_finish_with_failure(grpc_transport_op *op) {
|
||||
if (op->send_ops) {
|
||||
op->on_done_send(op->send_user_data, 0);
|
||||
|
|
@ -93,6 +103,9 @@ void grpc_transport_op_finish_with_failure(grpc_transport_op *op) {
|
|||
if (op->recv_ops) {
|
||||
op->on_done_recv(op->recv_user_data, 0);
|
||||
}
|
||||
if (op->on_consumed) {
|
||||
op->on_consumed(op->on_consumed_user_data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_transport_op_add_cancellation(grpc_transport_op *op,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "src/core/iomgr/pollset.h"
|
||||
#include "src/core/iomgr/pollset_set.h"
|
||||
#include "src/core/transport/stream_op.h"
|
||||
#include "src/core/channel/context.h"
|
||||
|
||||
|
|
@ -63,6 +64,9 @@ typedef enum grpc_stream_state {
|
|||
|
||||
/* Transport op: a set of operations to perform on a transport */
|
||||
typedef struct grpc_transport_op {
|
||||
void (*on_consumed)(void *user_data, int success);
|
||||
void *on_consumed_user_data;
|
||||
|
||||
grpc_stream_op_buffer *send_ops;
|
||||
int is_last_send;
|
||||
void (*on_done_send)(void *user_data, int success);
|
||||
|
|
@ -195,6 +199,10 @@ typedef struct grpc_transport_setup_vtable grpc_transport_setup_vtable;
|
|||
|
||||
struct grpc_transport_setup_vtable {
|
||||
void (*initiate)(grpc_transport_setup *setup);
|
||||
void (*add_interested_party)(grpc_transport_setup *setup,
|
||||
grpc_pollset *pollset);
|
||||
void (*del_interested_party)(grpc_transport_setup *setup,
|
||||
grpc_pollset *pollset);
|
||||
void (*cancel)(grpc_transport_setup *setup);
|
||||
};
|
||||
|
||||
|
|
@ -211,6 +219,12 @@ struct grpc_transport_setup {
|
|||
This *may* be implemented as a no-op if the setup process monitors something
|
||||
continuously. */
|
||||
void grpc_transport_setup_initiate(grpc_transport_setup *setup);
|
||||
|
||||
void grpc_transport_setup_add_interested_party(grpc_transport_setup *setup,
|
||||
grpc_pollset *pollset);
|
||||
void grpc_transport_setup_del_interested_party(grpc_transport_setup *setup,
|
||||
grpc_pollset *pollset);
|
||||
|
||||
/* Cancel transport setup. After this returns, no new transports should be
|
||||
created, and all pending transport setup callbacks should be completed.
|
||||
After this call completes, setup should be considered invalid (this can be
|
||||
|
|
|
|||
|
|
@ -54,8 +54,16 @@
|
|||
#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
|
||||
#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
|
||||
|
||||
|
||||
/* Putting a macro like this and littering the source file with #if is really
|
||||
bad practice.
|
||||
TODO(jboeuf): refactor all the #if / #endif in a separate module. */
|
||||
#ifndef TSI_OPENSSL_ALPN_SUPPORT
|
||||
#define TSI_OPENSSL_ALPN_SUPPORT 1
|
||||
#endif
|
||||
|
||||
/* TODO(jboeuf): I have not found a way to get this number dynamically from the
|
||||
* SSL structure. This is what we would ultimately want though... */
|
||||
SSL structure. This is what we would ultimately want though... */
|
||||
#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
|
||||
|
||||
/* --- Structure definitions. ---*/
|
||||
|
|
@ -70,6 +78,8 @@ struct tsi_ssl_handshaker_factory {
|
|||
typedef struct {
|
||||
tsi_ssl_handshaker_factory base;
|
||||
SSL_CTX* ssl_context;
|
||||
unsigned char* alpn_protocol_list;
|
||||
size_t alpn_protocol_list_length;
|
||||
} tsi_ssl_client_handshaker_factory;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -841,7 +851,7 @@ static tsi_result ssl_handshaker_process_bytes_from_peer(
|
|||
static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
|
||||
tsi_peer* peer) {
|
||||
tsi_result result = TSI_OK;
|
||||
const unsigned char* alpn_selected;
|
||||
const unsigned char* alpn_selected = NULL;
|
||||
unsigned int alpn_selected_len;
|
||||
tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
|
||||
X509* peer_cert = SSL_get_peer_certificate(impl->ssl);
|
||||
|
|
@ -850,7 +860,14 @@ static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
|
|||
X509_free(peer_cert);
|
||||
if (result != TSI_OK) return result;
|
||||
}
|
||||
#if TSI_OPENSSL_ALPN_SUPPORT
|
||||
SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
|
||||
#endif /* TSI_OPENSSL_ALPN_SUPPORT */
|
||||
if (alpn_selected == NULL) {
|
||||
/* Try npn. */
|
||||
SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
|
||||
&alpn_selected_len);
|
||||
}
|
||||
if (alpn_selected != NULL) {
|
||||
size_t i;
|
||||
tsi_peer_property* new_properties =
|
||||
|
|
@ -1012,6 +1029,32 @@ static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
|
|||
return TSI_OK;
|
||||
}
|
||||
|
||||
static int select_protocol_list(const unsigned char** out,
|
||||
unsigned char* outlen,
|
||||
const unsigned char* client_list,
|
||||
unsigned int client_list_len,
|
||||
const unsigned char* server_list,
|
||||
unsigned int server_list_len) {
|
||||
const unsigned char* client_current = client_list;
|
||||
while ((unsigned int)(client_current - client_list) < client_list_len) {
|
||||
unsigned char client_current_len = *(client_current++);
|
||||
const unsigned char* server_current = server_list;
|
||||
while ((server_current >= server_list) &&
|
||||
(gpr_uintptr)(server_current - server_list) < server_list_len) {
|
||||
unsigned char server_current_len = *(server_current++);
|
||||
if ((client_current_len == server_current_len) &&
|
||||
!memcmp(client_current, server_current, server_current_len)) {
|
||||
*out = server_current;
|
||||
*outlen = server_current_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
server_current += server_current_len;
|
||||
}
|
||||
client_current += client_current_len;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
|
||||
|
||||
static tsi_result ssl_client_handshaker_factory_create_handshaker(
|
||||
|
|
@ -1027,10 +1070,21 @@ static void ssl_client_handshaker_factory_destroy(
|
|||
tsi_ssl_handshaker_factory* self) {
|
||||
tsi_ssl_client_handshaker_factory* impl =
|
||||
(tsi_ssl_client_handshaker_factory*)self;
|
||||
SSL_CTX_free(impl->ssl_context);
|
||||
if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context);
|
||||
if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
|
||||
free(impl);
|
||||
}
|
||||
|
||||
static int client_handshaker_factory_npn_callback(
|
||||
SSL* ssl, unsigned char** out, unsigned char* outlen,
|
||||
const unsigned char* in, unsigned int inlen, void* arg) {
|
||||
tsi_ssl_client_handshaker_factory* factory =
|
||||
(tsi_ssl_client_handshaker_factory*)arg;
|
||||
return select_protocol_list((const unsigned char**)out, outlen,
|
||||
factory->alpn_protocol_list,
|
||||
factory->alpn_protocol_list_length, in, inlen);
|
||||
}
|
||||
|
||||
/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
|
||||
|
||||
static tsi_result ssl_server_handshaker_factory_create_handshaker(
|
||||
|
|
@ -1134,30 +1188,25 @@ static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap,
|
|||
return SSL_TLSEXT_ERR_ALERT_WARNING;
|
||||
}
|
||||
|
||||
#if TSI_OPENSSL_ALPN_SUPPORT
|
||||
static int server_handshaker_factory_alpn_callback(
|
||||
SSL* ssl, const unsigned char** out, unsigned char* outlen,
|
||||
const unsigned char* in, unsigned int inlen, void* arg) {
|
||||
tsi_ssl_server_handshaker_factory* factory =
|
||||
(tsi_ssl_server_handshaker_factory*)arg;
|
||||
const unsigned char* client_current = in;
|
||||
while ((unsigned int)(client_current - in) < inlen) {
|
||||
unsigned char client_current_len = *(client_current++);
|
||||
const unsigned char* server_current = factory->alpn_protocol_list;
|
||||
while ((server_current >= factory->alpn_protocol_list) &&
|
||||
(gpr_uintptr)(server_current - factory->alpn_protocol_list) <
|
||||
factory->alpn_protocol_list_length) {
|
||||
unsigned char server_current_len = *(server_current++);
|
||||
if ((client_current_len == server_current_len) &&
|
||||
!memcmp(client_current, server_current, server_current_len)) {
|
||||
*out = server_current;
|
||||
*outlen = server_current_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
server_current += server_current_len;
|
||||
}
|
||||
client_current += client_current_len;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
return select_protocol_list(out, outlen, in, inlen,
|
||||
factory->alpn_protocol_list,
|
||||
factory->alpn_protocol_list_length);
|
||||
}
|
||||
#endif /* TSI_OPENSSL_ALPN_SUPPORT */
|
||||
|
||||
static int server_handshaker_factory_npn_advertised_callback(
|
||||
SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) {
|
||||
tsi_ssl_server_handshaker_factory* factory =
|
||||
(tsi_ssl_server_handshaker_factory*)arg;
|
||||
*out = factory->alpn_protocol_list;
|
||||
*outlen = factory->alpn_protocol_list_length;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
/* --- tsi_ssl_handshaker_factory constructors. --- */
|
||||
|
|
@ -1184,6 +1233,14 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
|
|||
gpr_log(GPR_ERROR, "Could not create ssl context.");
|
||||
return TSI_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory));
|
||||
if (impl == NULL) {
|
||||
SSL_CTX_free(ssl_context);
|
||||
return TSI_OUT_OF_RESOURCES;
|
||||
}
|
||||
impl->ssl_context = ssl_context;
|
||||
|
||||
do {
|
||||
result =
|
||||
populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size,
|
||||
|
|
@ -1197,41 +1254,33 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
|
|||
}
|
||||
|
||||
if (num_alpn_protocols != 0) {
|
||||
unsigned char* alpn_protocol_list = NULL;
|
||||
size_t alpn_protocol_list_length = 0;
|
||||
int ssl_failed;
|
||||
result = build_alpn_protocol_name_list(
|
||||
alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
|
||||
&alpn_protocol_list, &alpn_protocol_list_length);
|
||||
&impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
|
||||
if (result != TSI_OK) {
|
||||
gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
|
||||
tsi_result_to_string(result));
|
||||
free(alpn_protocol_list);
|
||||
break;
|
||||
}
|
||||
ssl_failed = SSL_CTX_set_alpn_protos(ssl_context, alpn_protocol_list,
|
||||
alpn_protocol_list_length);
|
||||
free(alpn_protocol_list);
|
||||
if (ssl_failed) {
|
||||
#if TSI_OPENSSL_ALPN_SUPPORT
|
||||
if (SSL_CTX_set_alpn_protos(ssl_context, impl->alpn_protocol_list,
|
||||
impl->alpn_protocol_list_length)) {
|
||||
gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
|
||||
result = TSI_INVALID_ARGUMENT;
|
||||
break;
|
||||
}
|
||||
#endif /* TSI_OPENSSL_ALPN_SUPPORT */
|
||||
SSL_CTX_set_next_proto_select_cb(
|
||||
ssl_context, client_handshaker_factory_npn_callback, impl);
|
||||
}
|
||||
} while (0);
|
||||
if (result != TSI_OK) {
|
||||
SSL_CTX_free(ssl_context);
|
||||
ssl_client_handshaker_factory_destroy(&impl->base);
|
||||
return result;
|
||||
}
|
||||
SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
|
||||
/* TODO(jboeuf): Add revocation verification. */
|
||||
|
||||
impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory));
|
||||
if (impl == NULL) {
|
||||
SSL_CTX_free(ssl_context);
|
||||
return TSI_OUT_OF_RESOURCES;
|
||||
}
|
||||
impl->ssl_context = ssl_context;
|
||||
impl->base.create_handshaker =
|
||||
ssl_client_handshaker_factory_create_handshaker;
|
||||
impl->base.destroy = ssl_client_handshaker_factory_destroy;
|
||||
|
|
@ -1322,8 +1371,13 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
|
|||
impl->ssl_contexts[i],
|
||||
ssl_server_handshaker_factory_servername_callback);
|
||||
SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
|
||||
#if TSI_OPENSSL_ALPN_SUPPORT
|
||||
SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
|
||||
server_handshaker_factory_alpn_callback, impl);
|
||||
#endif /* TSI_OPENSSL_ALPN_SUPPORT */
|
||||
SSL_CTX_set_next_protos_advertised_cb(
|
||||
impl->ssl_contexts[i],
|
||||
server_handshaker_factory_npn_advertised_callback, impl);
|
||||
} while (0);
|
||||
|
||||
if (result != TSI_OK) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <grpc++/channel_arguments.h>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include "src/core/channel/channel_args.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
|
|
@ -41,6 +42,10 @@ void ChannelArguments::SetSslTargetNameOverride(const grpc::string& name) {
|
|||
SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetCompressionLevel(grpc_compression_level level) {
|
||||
SetInt(GRPC_COMPRESSION_LEVEL_ARG, level);
|
||||
}
|
||||
|
||||
grpc::string ChannelArguments::GetSslTargetNameOverride() const {
|
||||
for (unsigned int i = 0; i < args_.size(); i++) {
|
||||
if (grpc::string(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == args_[i].key) {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
|
|||
buf.AddClientSendClose();
|
||||
buf.AddClientRecvStatus(context, &status);
|
||||
call.PerformOps(&buf);
|
||||
GPR_ASSERT((cq.Pluck(&buf) && buf.got_message) || !status.IsOk());
|
||||
GPR_ASSERT((cq.Pluck(&buf) && buf.got_message) || !status.ok());
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,8 +214,8 @@ void CallOpBuffer::AddServerSendStatus(
|
|||
trailing_metadata_count_ = 0;
|
||||
}
|
||||
send_status_available_ = true;
|
||||
send_status_code_ = static_cast<grpc_status_code>(status.code());
|
||||
send_status_details_ = status.details();
|
||||
send_status_code_ = static_cast<grpc_status_code>(status.error_code());
|
||||
send_status_details_ = status.error_message();
|
||||
}
|
||||
|
||||
void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
|
||||
|
|
@ -224,11 +224,13 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
|
|||
ops[*nops].op = GRPC_OP_SEND_INITIAL_METADATA;
|
||||
ops[*nops].data.send_initial_metadata.count = initial_metadata_count_;
|
||||
ops[*nops].data.send_initial_metadata.metadata = initial_metadata_;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (recv_initial_metadata_) {
|
||||
ops[*nops].op = GRPC_OP_RECV_INITIAL_METADATA;
|
||||
ops[*nops].data.recv_initial_metadata = &recv_initial_metadata_arr_;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (send_message_ || send_message_buffer_) {
|
||||
|
|
@ -245,15 +247,18 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
|
|||
}
|
||||
ops[*nops].op = GRPC_OP_SEND_MESSAGE;
|
||||
ops[*nops].data.send_message = send_buf_;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (recv_message_ || recv_message_buffer_) {
|
||||
ops[*nops].op = GRPC_OP_RECV_MESSAGE;
|
||||
ops[*nops].data.recv_message = &recv_buf_;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (client_send_close_) {
|
||||
ops[*nops].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (recv_status_) {
|
||||
|
|
@ -264,6 +269,7 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
|
|||
ops[*nops].data.recv_status_on_client.status_details = &status_details_;
|
||||
ops[*nops].data.recv_status_on_client.status_details_capacity =
|
||||
&status_details_capacity_;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (send_status_available_) {
|
||||
|
|
@ -275,11 +281,13 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
|
|||
ops[*nops].data.send_status_from_server.status = send_status_code_;
|
||||
ops[*nops].data.send_status_from_server.status_details =
|
||||
send_status_details_.empty() ? nullptr : send_status_details_.c_str();
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
if (recv_closed_) {
|
||||
ops[*nops].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
|
||||
ops[*nops].data.recv_close_on_server.cancelled = &cancelled_buf_;
|
||||
ops[*nops].flags = 0;
|
||||
(*nops)++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,14 @@
|
|||
|
||||
namespace grpc {
|
||||
|
||||
class Server::ShutdownRequest GRPC_FINAL : public CompletionQueueTag {
|
||||
public:
|
||||
bool FinalizeResult(void** tag, bool* status) {
|
||||
delete this;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
|
||||
public:
|
||||
SyncRequest(RpcServiceMethod* method, void* tag)
|
||||
|
|
@ -63,7 +71,8 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
|
|||
RpcMethod::SERVER_STREAMING),
|
||||
has_response_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
|
||||
method->method_type() ==
|
||||
RpcMethod::CLIENT_STREAMING) {
|
||||
RpcMethod::CLIENT_STREAMING),
|
||||
cq_(nullptr) {
|
||||
grpc_metadata_array_init(&request_metadata_);
|
||||
}
|
||||
|
||||
|
|
@ -82,10 +91,18 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
|
|||
return mrd;
|
||||
}
|
||||
|
||||
void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
|
||||
GPR_ASSERT(!in_flight_);
|
||||
in_flight_ = true;
|
||||
void SetupRequest() {
|
||||
cq_ = grpc_completion_queue_create();
|
||||
}
|
||||
|
||||
void TeardownRequest() {
|
||||
grpc_completion_queue_destroy(cq_);
|
||||
cq_ = nullptr;
|
||||
}
|
||||
|
||||
void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
|
||||
GPR_ASSERT(cq_ && !in_flight_);
|
||||
in_flight_ = true;
|
||||
GPR_ASSERT(GRPC_CALL_OK ==
|
||||
grpc_server_request_registered_call(
|
||||
server, tag_, &call_, &deadline_, &request_metadata_,
|
||||
|
|
@ -217,6 +234,9 @@ Server::~Server() {
|
|||
Shutdown();
|
||||
}
|
||||
}
|
||||
void* got_tag;
|
||||
bool ok;
|
||||
GPR_ASSERT(!cq_.Next(&got_tag, &ok));
|
||||
grpc_server_destroy(server_);
|
||||
if (thread_pool_owned_) {
|
||||
delete thread_pool_;
|
||||
|
|
@ -277,6 +297,7 @@ bool Server::Start() {
|
|||
// Start processing rpcs.
|
||||
if (!sync_methods_->empty()) {
|
||||
for (auto m = sync_methods_->begin(); m != sync_methods_->end(); m++) {
|
||||
m->SetupRequest();
|
||||
m->Request(server_, cq_.cq());
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +311,7 @@ void Server::Shutdown() {
|
|||
grpc::unique_lock<grpc::mutex> lock(mu_);
|
||||
if (started_ && !shutdown_) {
|
||||
shutdown_ = true;
|
||||
grpc_server_shutdown(server_);
|
||||
grpc_server_shutdown_and_notify(server_, cq_.cq(), new ShutdownRequest());
|
||||
cq_.Shutdown();
|
||||
|
||||
// Wait for running callbacks to finish.
|
||||
|
|
@ -461,9 +482,13 @@ void Server::RunRpc() {
|
|||
if (ok) {
|
||||
SyncRequest::CallData cd(this, mrd);
|
||||
{
|
||||
mrd->SetupRequest();
|
||||
grpc::unique_lock<grpc::mutex> lock(mu_);
|
||||
if (!shutdown_) {
|
||||
mrd->Request(server_, cq_.cq());
|
||||
} else {
|
||||
// destroy the structure that was created
|
||||
mrd->TeardownRequest();
|
||||
}
|
||||
}
|
||||
cd.Run();
|
||||
|
|
|
|||
|
|
@ -36,6 +36,6 @@
|
|||
namespace grpc {
|
||||
|
||||
const Status& Status::OK = Status();
|
||||
const Status& Status::Cancelled = Status(StatusCode::CANCELLED);
|
||||
const Status& Status::CANCELLED = Status(StatusCode::CANCELLED, "");
|
||||
|
||||
} // namespace grpc
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ namespace Grpc.Core.Tests
|
|||
BenchmarkUtil.RunBenchmark(100, 100,
|
||||
() => { Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)); });
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void UnknownMethodHandler()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ namespace Grpc.Core.Internal
|
|||
|
||||
call.StartSendStatusFromServer(status, HandleHalfclosed);
|
||||
halfcloseRequested = true;
|
||||
readingDone = true;
|
||||
sendCompletionDelegate = completionDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,7 +192,5 @@ namespace Grpc.Core.Internal
|
|||
{
|
||||
return buffered ? 0 : GRPC_WRITE_BUFFER_HINT;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -32,14 +32,15 @@
|
|||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Grpc.Core.Utils;
|
||||
|
||||
namespace Grpc.Core.Internal
|
||||
{
|
||||
internal delegate void OpCompletionDelegate(bool success);
|
||||
|
||||
internal delegate void BatchCompletionDelegate(bool success, BatchContextSafeHandle ctx);
|
||||
|
||||
internal class CompletionRegistry
|
||||
|
|
|
|||
|
|
@ -267,8 +267,6 @@ namespace Grpc.Core.Internal
|
|||
var responseStream = new ServerResponseStream<byte[], byte[]>(asyncCall);
|
||||
|
||||
await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, "No such method."));
|
||||
// TODO(jtattermusch): if we don't read what client has sent, the server call never gets disposed.
|
||||
await requestStream.ToList();
|
||||
await finishedTask;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ namespace Grpc.Core.Internal
|
|||
static extern GRPCCallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
|
||||
|
||||
[DllImport("grpc_csharp_ext.dll")]
|
||||
static extern void grpcsharp_server_shutdown(ServerSafeHandle server);
|
||||
static extern void grpcsharp_server_cancel_all_calls(ServerSafeHandle server);
|
||||
|
||||
[DllImport("grpc_csharp_ext.dll")]
|
||||
static extern void grpcsharp_server_shutdown_and_notify_callback(ServerSafeHandle server, BatchContextSafeHandle ctx);
|
||||
static extern void grpcsharp_server_shutdown_and_notify_callback(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
|
||||
|
||||
[DllImport("grpc_csharp_ext.dll")]
|
||||
static extern void grpcsharp_server_destroy(IntPtr server);
|
||||
|
|
@ -91,17 +91,12 @@ namespace Grpc.Core.Internal
|
|||
{
|
||||
grpcsharp_server_start(this);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
grpcsharp_server_shutdown(this);
|
||||
}
|
||||
|
||||
public void ShutdownAndNotify(BatchCompletionDelegate callback)
|
||||
|
||||
public void ShutdownAndNotify(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
|
||||
{
|
||||
var ctx = BatchContextSafeHandle.Create();
|
||||
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
|
||||
grpcsharp_server_shutdown_and_notify_callback(this, ctx);
|
||||
grpcsharp_server_shutdown_and_notify_callback(this, cq, ctx);
|
||||
}
|
||||
|
||||
public void RequestCall(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
|
||||
|
|
@ -116,5 +111,11 @@ namespace Grpc.Core.Internal
|
|||
grpcsharp_server_destroy(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only to be called after ShutdownAndNotify.
|
||||
public void CancelAllCalls()
|
||||
{
|
||||
grpcsharp_server_cancel_all_calls(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,8 @@ namespace Grpc.Core
|
|||
Preconditions.CheckState(!shutdownRequested);
|
||||
shutdownRequested = true;
|
||||
}
|
||||
handle.ShutdownAndNotify(HandleServerShutdown);
|
||||
|
||||
handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
|
||||
await shutdownTcs.Task;
|
||||
handle.Dispose();
|
||||
}
|
||||
|
|
@ -159,8 +160,22 @@ namespace Grpc.Core
|
|||
}
|
||||
}
|
||||
|
||||
public void Kill()
|
||||
/// <summary>
|
||||
/// Requests server shutdown while cancelling all the in-progress calls.
|
||||
/// The returned task finishes when shutdown procedure is complete.
|
||||
/// </summary>
|
||||
public async Task KillAsync()
|
||||
{
|
||||
lock (myLock)
|
||||
{
|
||||
Preconditions.CheckState(startRequested);
|
||||
Preconditions.CheckState(!shutdownRequested);
|
||||
shutdownRequested = true;
|
||||
}
|
||||
|
||||
handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
|
||||
handle.CancelAllCalls();
|
||||
await shutdownTcs.Task;
|
||||
handle.Dispose();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,18 +417,23 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
|
|||
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
|
||||
ops[0].data.send_initial_metadata.metadata =
|
||||
ctx->send_initial_metadata.metadata;
|
||||
ops[0].flags = 0;
|
||||
|
||||
ops[1].op = GRPC_OP_SEND_MESSAGE;
|
||||
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
|
||||
ops[1].data.send_message = ctx->send_message;
|
||||
ops[1].flags = 0;
|
||||
|
||||
ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
|
||||
ops[2].flags = 0;
|
||||
|
||||
ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
|
||||
ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
|
||||
ops[3].flags = 0;
|
||||
|
||||
ops[4].op = GRPC_OP_RECV_MESSAGE;
|
||||
ops[4].data.recv_message = &(ctx->recv_message);
|
||||
ops[4].flags = 0;
|
||||
|
||||
ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
|
||||
ops[5].data.recv_status_on_client.trailing_metadata =
|
||||
|
|
@ -440,6 +445,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
|
|||
&(ctx->recv_status_on_client.status_details);
|
||||
ops[5].data.recv_status_on_client.status_details_capacity =
|
||||
&(ctx->recv_status_on_client.status_details_capacity);
|
||||
ops[5].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -456,12 +462,15 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
|
|||
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
|
||||
ops[0].data.send_initial_metadata.metadata =
|
||||
ctx->send_initial_metadata.metadata;
|
||||
ops[0].flags = 0;
|
||||
|
||||
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
|
||||
ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
|
||||
ops[1].flags = 0;
|
||||
|
||||
ops[2].op = GRPC_OP_RECV_MESSAGE;
|
||||
ops[2].data.recv_message = &(ctx->recv_message);
|
||||
ops[2].flags = 0;
|
||||
|
||||
ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
|
||||
ops[3].data.recv_status_on_client.trailing_metadata =
|
||||
|
|
@ -473,6 +482,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
|
|||
&(ctx->recv_status_on_client.status_details);
|
||||
ops[3].data.recv_status_on_client.status_details_capacity =
|
||||
&(ctx->recv_status_on_client.status_details_capacity);
|
||||
ops[3].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -488,15 +498,19 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
|
|||
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
|
||||
ops[0].data.send_initial_metadata.metadata =
|
||||
ctx->send_initial_metadata.metadata;
|
||||
ops[0].flags = 0;
|
||||
|
||||
ops[1].op = GRPC_OP_SEND_MESSAGE;
|
||||
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
|
||||
ops[1].data.send_message = ctx->send_message;
|
||||
ops[1].flags = 0;
|
||||
|
||||
ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
|
||||
ops[2].flags = 0;
|
||||
|
||||
ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
|
||||
ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
|
||||
ops[3].flags = 0;
|
||||
|
||||
ops[4].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
|
||||
ops[4].data.recv_status_on_client.trailing_metadata =
|
||||
|
|
@ -508,6 +522,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
|
|||
&(ctx->recv_status_on_client.status_details);
|
||||
ops[4].data.recv_status_on_client.status_details_capacity =
|
||||
&(ctx->recv_status_on_client.status_details_capacity);
|
||||
ops[4].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -524,9 +539,11 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
|
|||
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
|
||||
ops[0].data.send_initial_metadata.metadata =
|
||||
ctx->send_initial_metadata.metadata;
|
||||
ops[0].flags = 0;
|
||||
|
||||
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
|
||||
ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
|
||||
ops[1].flags = 0;
|
||||
|
||||
ops[2].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
|
||||
ops[2].data.recv_status_on_client.trailing_metadata =
|
||||
|
|
@ -538,6 +555,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
|
|||
&(ctx->recv_status_on_client.status_details);
|
||||
ops[2].data.recv_status_on_client.status_details_capacity =
|
||||
&(ctx->recv_status_on_client.status_details_capacity);
|
||||
ops[2].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -550,6 +568,7 @@ grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx,
|
|||
ops[0].op = GRPC_OP_SEND_MESSAGE;
|
||||
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
|
||||
ops[0].data.send_message = ctx->send_message;
|
||||
ops[0].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -560,6 +579,7 @@ grpcsharp_call_send_close_from_client(grpc_call *call,
|
|||
/* TODO: don't use magic number */
|
||||
grpc_op ops[1];
|
||||
ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
|
||||
ops[0].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -577,6 +597,7 @@ grpcsharp_call_send_status_from_server(grpc_call *call,
|
|||
gpr_strdup(status_details);
|
||||
ops[0].data.send_status_from_server.trailing_metadata = NULL;
|
||||
ops[0].data.send_status_from_server.trailing_metadata_count = 0;
|
||||
ops[0].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -587,6 +608,7 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) {
|
|||
grpc_op ops[1];
|
||||
ops[0].op = GRPC_OP_RECV_MESSAGE;
|
||||
ops[0].data.recv_message = &(ctx->recv_message);
|
||||
ops[0].flags = 0;
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
||||
|
|
@ -597,10 +619,12 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) {
|
|||
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
|
||||
ops[0].data.send_initial_metadata.count = 0;
|
||||
ops[0].data.send_initial_metadata.metadata = NULL;
|
||||
ops[0].flags = 0;
|
||||
|
||||
ops[1].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
|
||||
ops[1].data.recv_close_on_server.cancelled =
|
||||
(&ctx->recv_close_on_server_cancelled);
|
||||
ops[1].flags = 0;
|
||||
|
||||
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
|
||||
}
|
||||
|
|
@ -624,14 +648,15 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_start(grpc_server *server) {
|
|||
grpc_server_start(server);
|
||||
}
|
||||
|
||||
GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_shutdown(grpc_server *server) {
|
||||
grpc_server_shutdown(server);
|
||||
}
|
||||
|
||||
GPR_EXPORT void GPR_CALLTYPE
|
||||
grpcsharp_server_shutdown_and_notify_callback(grpc_server *server,
|
||||
grpc_completion_queue *cq,
|
||||
grpcsharp_batch_context *ctx) {
|
||||
grpc_server_shutdown_and_notify(server, ctx);
|
||||
grpc_server_shutdown_and_notify(server, cq, ctx);
|
||||
}
|
||||
|
||||
GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_cancel_all_calls(grpc_server *server) {
|
||||
grpc_server_cancel_all_calls(server);
|
||||
}
|
||||
|
||||
GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_destroy(grpc_server *server) {
|
||||
|
|
|
|||
|
|
@ -550,6 +550,7 @@ NAN_METHOD(Call::StartBatch) {
|
|||
}
|
||||
uint32_t type = keys->Get(i)->Uint32Value();
|
||||
ops[i].op = static_cast<grpc_op_type>(type);
|
||||
ops[i].flags = 0;
|
||||
switch (type) {
|
||||
case GRPC_OP_SEND_INITIAL_METADATA:
|
||||
op.reset(new SendMetadataOp());
|
||||
|
|
|
|||
|
|
@ -112,9 +112,17 @@ class NewCallOp : public Op {
|
|||
}
|
||||
};
|
||||
|
||||
Server::Server(grpc_server *server) : wrapped_server(server) {}
|
||||
Server::Server(grpc_server *server) : wrapped_server(server) {
|
||||
shutdown_queue = grpc_completion_queue_create();
|
||||
grpc_server_register_completion_queue(server, shutdown_queue);
|
||||
}
|
||||
|
||||
Server::~Server() { grpc_server_destroy(wrapped_server); }
|
||||
Server::~Server() {
|
||||
this->ShutdownServer();
|
||||
grpc_completion_queue_shutdown(this->shutdown_queue);
|
||||
grpc_server_destroy(wrapped_server);
|
||||
grpc_completion_queue_destroy(this->shutdown_queue);
|
||||
}
|
||||
|
||||
void Server::Init(Handle<Object> exports) {
|
||||
NanScope();
|
||||
|
|
@ -148,6 +156,16 @@ bool Server::HasInstance(Handle<Value> val) {
|
|||
return NanHasInstance(fun_tpl, val);
|
||||
}
|
||||
|
||||
void Server::ShutdownServer() {
|
||||
if (this->wrapped_server != NULL) {
|
||||
grpc_server_shutdown_and_notify(this->wrapped_server,
|
||||
this->shutdown_queue,
|
||||
NULL);
|
||||
grpc_completion_queue_pluck(this->shutdown_queue, NULL, gpr_inf_future);
|
||||
this->wrapped_server = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(Server::New) {
|
||||
NanScope();
|
||||
|
||||
|
|
@ -207,6 +225,9 @@ NAN_METHOD(Server::RequestCall) {
|
|||
return NanThrowTypeError("requestCall can only be called on a Server");
|
||||
}
|
||||
Server *server = ObjectWrap::Unwrap<Server>(args.This());
|
||||
if (server->wrapped_server == NULL) {
|
||||
return NanThrowError("requestCall cannot be called on a shut down Server");
|
||||
}
|
||||
NewCallOp *op = new NewCallOp();
|
||||
unique_ptr<OpVec> ops(new OpVec());
|
||||
ops->push_back(unique_ptr<Op>(op));
|
||||
|
|
@ -232,6 +253,9 @@ NAN_METHOD(Server::AddHttp2Port) {
|
|||
return NanThrowTypeError("addHttp2Port's argument must be a String");
|
||||
}
|
||||
Server *server = ObjectWrap::Unwrap<Server>(args.This());
|
||||
if (server->wrapped_server == NULL) {
|
||||
return NanThrowError("addHttp2Port cannot be called on a shut down Server");
|
||||
}
|
||||
NanReturnValue(NanNew<Number>(grpc_server_add_http2_port(
|
||||
server->wrapped_server, *NanUtf8String(args[0]))));
|
||||
}
|
||||
|
|
@ -251,6 +275,10 @@ NAN_METHOD(Server::AddSecureHttp2Port) {
|
|||
"addSecureHttp2Port's second argument must be ServerCredentials");
|
||||
}
|
||||
Server *server = ObjectWrap::Unwrap<Server>(args.This());
|
||||
if (server->wrapped_server == NULL) {
|
||||
return NanThrowError(
|
||||
"addSecureHttp2Port cannot be called on a shut down Server");
|
||||
}
|
||||
ServerCredentials *creds = ObjectWrap::Unwrap<ServerCredentials>(
|
||||
args[1]->ToObject());
|
||||
NanReturnValue(NanNew<Number>(grpc_server_add_secure_http2_port(
|
||||
|
|
@ -264,17 +292,24 @@ NAN_METHOD(Server::Start) {
|
|||
return NanThrowTypeError("start can only be called on a Server");
|
||||
}
|
||||
Server *server = ObjectWrap::Unwrap<Server>(args.This());
|
||||
if (server->wrapped_server == NULL) {
|
||||
return NanThrowError("start cannot be called on a shut down Server");
|
||||
}
|
||||
grpc_server_start(server->wrapped_server);
|
||||
NanReturnUndefined();
|
||||
}
|
||||
|
||||
NAN_METHOD(ShutdownCallback) {
|
||||
NanReturnUndefined();
|
||||
}
|
||||
|
||||
NAN_METHOD(Server::Shutdown) {
|
||||
NanScope();
|
||||
if (!HasInstance(args.This())) {
|
||||
return NanThrowTypeError("shutdown can only be called on a Server");
|
||||
}
|
||||
Server *server = ObjectWrap::Unwrap<Server>(args.This());
|
||||
grpc_server_shutdown(server->wrapped_server);
|
||||
server->ShutdownServer();
|
||||
NanReturnUndefined();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ class Server : public ::node::ObjectWrap {
|
|||
Server(const Server &);
|
||||
Server &operator=(const Server &);
|
||||
|
||||
void ShutdownServer();
|
||||
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(RequestCall);
|
||||
static NAN_METHOD(AddHttp2Port);
|
||||
|
|
@ -71,6 +73,7 @@ class Server : public ::node::ObjectWrap {
|
|||
static v8::Persistent<v8::FunctionTemplate> fun_tpl;
|
||||
|
||||
grpc_server *wrapped_server;
|
||||
grpc_completion_queue *shutdown_queue;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
|||
|
|
@ -31,43 +31,55 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// The gRPC protocol is an RPC protocol on top of HTTP2.
|
||||
//
|
||||
// While the most common type of RPC receives only one request message and returns only one response
|
||||
// message, the protocol also supports RPCs that return multiple individual messages in a streaming
|
||||
// fashion, RPCs that accept a stream of request messages, or RPCs with both streaming requests and
|
||||
// responses.
|
||||
//
|
||||
// Conceptually, each gRPC call consists of a bidirectional stream of binary messages, with RPCs of
|
||||
// the "non-streaming type" sending only one message in the corresponding direction (the protocol
|
||||
// doesn't make any distinction).
|
||||
//
|
||||
// Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs can be multiplexed
|
||||
// transparently on the same TCP connection.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <gRPC/GRXWriter.h>
|
||||
|
||||
@class GRPCMethodName;
|
||||
|
||||
@class GRPCCall;
|
||||
// Key used in |NSError|'s |userInfo| dictionary to store the response metadata sent by the server.
|
||||
extern id const kGRPCStatusMetadataKey;
|
||||
|
||||
// The gRPC protocol is an RPC protocol on top of HTTP2.
|
||||
//
|
||||
// While the most common type of RPC receives only one request message and
|
||||
// returns only one response message, the protocol also supports RPCs that
|
||||
// return multiple individual messages in a streaming fashion, RPCs that
|
||||
// accept a stream of request messages, or RPCs with both streaming requests
|
||||
// and responses.
|
||||
//
|
||||
// Conceptually, each gRPC call consists of a bidirectional stream of binary
|
||||
// messages, with RPCs of the "non-streaming type" sending only one message in
|
||||
// the corresponding direction (the protocol doesn't make any distinction).
|
||||
//
|
||||
// Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs
|
||||
// can be multiplexed transparently on the same TCP connection.
|
||||
// Represents a single gRPC remote call.
|
||||
@interface GRPCCall : NSObject<GRXWriter>
|
||||
|
||||
// These HTTP2 headers will be passed to the server as part of this call. Each
|
||||
// HTTP2 header is a name-value pair with string names and either string or binary values.
|
||||
// These HTTP headers will be passed to the server as part of this call. Each HTTP header is a
|
||||
// name-value pair with string names and either string or binary values.
|
||||
//
|
||||
// The passed dictionary has to use NSString keys, corresponding to the header names. The
|
||||
// value associated to each can be a NSString object or a NSData object. E.g.:
|
||||
//
|
||||
// call.requestMetadata = @{
|
||||
// @"Authorization": @"Bearer ...",
|
||||
// @"SomeBinaryHeader": someData
|
||||
// };
|
||||
// call.requestMetadata = @{@"Authorization": @"Bearer ..."};
|
||||
//
|
||||
// call.requestMetadata[@"SomeBinaryHeader"] = someData;
|
||||
//
|
||||
// After the call is started, modifying this won't have any effect.
|
||||
@property(nonatomic, readwrite) NSMutableDictionary *requestMetadata;
|
||||
//
|
||||
// For convenience, the property is initialized to an empty NSMutableDictionary, and the setter
|
||||
// accepts (and copies) both mutable and immutable dictionaries.
|
||||
- (NSMutableDictionary *)requestMetadata; // nonatomic
|
||||
- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy
|
||||
|
||||
// This isn't populated until the first event is delivered to the handler.
|
||||
// This dictionary is populated with the HTTP headers received from the server. When the RPC ends,
|
||||
// the HTTP trailers received are added to the dictionary too. It has the same structure as the
|
||||
// request metadata dictionary.
|
||||
//
|
||||
// The first time this object calls |writeValue| on the writeable passed to |startWithWriteable|,
|
||||
// the |responseMetadata| dictionary already contains the response headers. When it calls
|
||||
// |writesFinishedWithError|, the dictionary contains both the response headers and trailers.
|
||||
@property(atomic, readonly) NSDictionary *responseMetadata;
|
||||
|
||||
// The request writer has to write NSData objects into the provided Writeable. The server will
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@
|
|||
#import "private/NSDictionary+GRPC.h"
|
||||
#import "private/NSError+GRPC.h"
|
||||
|
||||
NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
|
||||
|
||||
@interface GRPCCall () <GRXWriteable>
|
||||
// Makes it readwrite.
|
||||
@property(atomic, strong) NSDictionary *responseMetadata;
|
||||
@end
|
||||
|
||||
// The following methods of a C gRPC call object aren't reentrant, and thus
|
||||
|
|
@ -82,6 +82,9 @@
|
|||
// correct ordering.
|
||||
GRPCDelegateWrapper *_responseWriteable;
|
||||
id<GRXWriter> _requestWriter;
|
||||
|
||||
NSMutableDictionary *_requestMetadata;
|
||||
NSMutableDictionary *_responseMetadata;
|
||||
}
|
||||
|
||||
@synthesize state = _state;
|
||||
|
|
@ -97,7 +100,9 @@
|
|||
if (!host || !method) {
|
||||
[NSException raise:NSInvalidArgumentException format:@"Neither host nor method can be nil."];
|
||||
}
|
||||
// TODO(jcanizales): Throw if the requestWriter was already started.
|
||||
if (requestWriter.state != GRXWriterStateNotStarted) {
|
||||
[NSException raise:NSInvalidArgumentException format:@"The requests writer can't be already started."];
|
||||
}
|
||||
if ((self = [super init])) {
|
||||
static dispatch_once_t initialization;
|
||||
dispatch_once(&initialization, ^{
|
||||
|
|
@ -116,10 +121,27 @@
|
|||
_callQueue = dispatch_queue_create("org.grpc.call", NULL);
|
||||
|
||||
_requestWriter = requestWriter;
|
||||
|
||||
_requestMetadata = [NSMutableDictionary dictionary];
|
||||
_responseMetadata = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Metadata
|
||||
|
||||
- (NSMutableDictionary *)requestMetadata {
|
||||
return _requestMetadata;
|
||||
}
|
||||
|
||||
- (void)setRequestMetadata:(NSDictionary *)requestMetadata {
|
||||
_requestMetadata = [NSMutableDictionary dictionaryWithDictionary:requestMetadata];
|
||||
}
|
||||
|
||||
- (NSDictionary *)responseMetadata {
|
||||
return _responseMetadata;
|
||||
}
|
||||
|
||||
#pragma mark Finish
|
||||
|
||||
- (void)finishWithError:(NSError *)errorOrNil {
|
||||
|
|
@ -277,7 +299,7 @@
|
|||
// The first one (metadataHandler), when the response headers are received.
|
||||
// The second one (completionHandler), whenever the RPC finishes for any reason.
|
||||
- (void)invokeCallWithMetadataHandler:(void(^)(NSDictionary *))metadataHandler
|
||||
completionHandler:(void(^)(NSError *))completionHandler {
|
||||
completionHandler:(void(^)(NSError *, NSDictionary *))completionHandler {
|
||||
// TODO(jcanizales): Add error handlers for async failures
|
||||
[_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvMetadata alloc]
|
||||
initWithHandler:metadataHandler]]];
|
||||
|
|
@ -287,16 +309,26 @@
|
|||
|
||||
- (void)invokeCall {
|
||||
__weak GRPCCall *weakSelf = self;
|
||||
[self invokeCallWithMetadataHandler:^(NSDictionary *metadata) {
|
||||
// Response metadata received.
|
||||
[self invokeCallWithMetadataHandler:^(NSDictionary *headers) {
|
||||
// Response headers received.
|
||||
GRPCCall *strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
strongSelf.responseMetadata = metadata;
|
||||
[strongSelf->_responseMetadata addEntriesFromDictionary:headers];
|
||||
[strongSelf startNextRead];
|
||||
}
|
||||
} completionHandler:^(NSError *error) {
|
||||
// TODO(jcanizales): Merge HTTP2 trailers into response metadata.
|
||||
[weakSelf finishWithError:error];
|
||||
} completionHandler:^(NSError *error, NSDictionary *trailers) {
|
||||
GRPCCall *strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[strongSelf->_responseMetadata addEntriesFromDictionary:trailers];
|
||||
|
||||
if (error) {
|
||||
NSMutableDictionary *userInfo =
|
||||
[NSMutableDictionary dictionaryWithDictionary:error.userInfo];
|
||||
userInfo[kGRPCStatusMetadataKey] = strongSelf->_responseMetadata;
|
||||
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
|
||||
}
|
||||
[strongSelf finishWithError:error];
|
||||
}
|
||||
}];
|
||||
// Now that the RPC has been initiated, request writes can start.
|
||||
[_requestWriter startWithWriteable:self];
|
||||
|
|
|
|||
|
|
@ -33,53 +33,51 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <grpc/grpc.h>
|
||||
|
||||
#import "GRPCChannel.h"
|
||||
|
||||
typedef void(^GRPCCompletionHandler)(NSDictionary *);
|
||||
|
||||
@protocol GRPCOp <NSObject>
|
||||
|
||||
- (void)getOp:(grpc_op *)op;
|
||||
|
||||
@interface GRPCOperation : NSObject
|
||||
@property(nonatomic, readonly) grpc_op op;
|
||||
// Guaranteed to be called when the operation has finished.
|
||||
- (void)finish;
|
||||
|
||||
@end
|
||||
|
||||
@interface GRPCOpSendMetadata : NSObject <GRPCOp>
|
||||
@interface GRPCOpSendMetadata : GRPCOperation
|
||||
|
||||
- (instancetype)initWithMetadata:(NSDictionary *)metadata
|
||||
handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
|
||||
handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@interface GRPCOpSendMessage : NSObject <GRPCOp>
|
||||
@interface GRPCOpSendMessage : GRPCOperation
|
||||
|
||||
- (instancetype)initWithMessage:(NSData *)message
|
||||
handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
|
||||
handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@interface GRPCOpSendClose : NSObject <GRPCOp>
|
||||
@interface GRPCOpSendClose : GRPCOperation
|
||||
|
||||
- (instancetype)initWithHandler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithHandler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@interface GRPCOpRecvMetadata : NSObject <GRPCOp>
|
||||
@interface GRPCOpRecvMetadata : GRPCOperation
|
||||
|
||||
- (instancetype)initWithHandler:(void(^)(NSDictionary *))handler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@interface GRPCOpRecvMessage : NSObject <GRPCOp>
|
||||
@interface GRPCOpRecvMessage : GRPCOperation
|
||||
|
||||
- (instancetype)initWithHandler:(void(^)(grpc_byte_buffer *))handler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@interface GRPCOpRecvStatus : NSObject <GRPCOp>
|
||||
@interface GRPCOpRecvStatus : GRPCOperation
|
||||
|
||||
- (instancetype)initWithHandler:(void(^)(NSError *))handler NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithHandler:(void(^)(NSError *, NSDictionary *))handler
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue