merge with head

pull/2702/head
yang-g 10 years ago
commit dcf6c90b33
  1. 3
      BUILD
  2. 1749
      Makefile
  3. 37
      build.json
  4. 1
      gRPC.podspec
  5. 1
      include/grpc++/dynamic_thread_pool.h
  6. 2
      include/grpc++/impl/sync_no_cxx11.h
  7. 3
      include/grpc++/server_context.h
  8. 32
      include/grpc/census.h
  9. 19
      include/grpc/grpc.h
  10. 12
      src/compiler/csharp_generator.cc
  11. 2
      src/core/census/grpc_context.c
  12. 19
      src/core/census/initialize.c
  13. 149
      src/core/channel/client_channel.c
  14. 14
      src/core/channel/client_channel.h
  15. 192
      src/core/client_config/lb_policies/pick_first.c
  16. 15
      src/core/client_config/lb_policy.c
  17. 12
      src/core/client_config/lb_policy.h
  18. 68
      src/core/client_config/subchannel.c
  19. 4
      src/core/iomgr/alarm.c
  20. 4
      src/core/iomgr/endpoint.c
  21. 3
      src/core/iomgr/endpoint.h
  22. 6
      src/core/iomgr/endpoint_pair_windows.c
  23. 1
      src/core/iomgr/iomgr.c
  24. 12
      src/core/iomgr/pollset_set_posix.c
  25. 33
      src/core/iomgr/tcp_client_posix.c
  26. 11
      src/core/iomgr/tcp_posix.c
  27. 22
      src/core/iomgr/tcp_server_windows.c
  28. 16
      src/core/iomgr/tcp_windows.c
  29. 12
      src/core/security/secure_endpoint.c
  30. 35
      src/core/support/stack_lockfree.c
  31. 191
      src/core/surface/channel_connectivity.c
  32. 10
      src/core/surface/channel_create.c
  33. 9
      src/core/surface/init.c
  34. 10
      src/core/surface/secure_channel_create.c
  35. 41
      src/core/transport/chttp2_transport.c
  36. 44
      src/core/transport/connectivity_state.c
  37. 13
      src/core/transport/connectivity_state.h
  38. 2
      src/core/transport/transport.h
  39. 4
      src/cpp/client/create_channel.cc
  40. 5
      src/cpp/server/server_context.cc
  41. 24
      src/csharp/ext/grpc_csharp_ext.c
  42. 3
      src/node/examples/perf_test.js
  43. 3
      src/node/examples/qps_test.js
  44. 3
      src/node/examples/route_guide_client.js
  45. 3
      src/node/examples/stock_client.js
  46. 52
      src/node/ext/channel.cc
  47. 47
      src/node/ext/credentials.cc
  48. 1
      src/node/ext/credentials.h
  49. 32
      src/node/index.js
  50. 8
      src/node/interop/interop_client.js
  51. 22
      src/node/jsdoc_conf.json
  52. 4
      src/node/package.json
  53. 31
      src/node/src/client.js
  54. 52
      src/node/src/common.js
  55. 45
      src/node/src/server.js
  56. 6
      src/node/test/call_test.js
  57. 33
      src/node/test/channel_test.js
  58. 4
      src/node/test/end_to_end_test.js
  59. 3
      src/node/test/health_test.js
  60. 3
      src/node/test/math_client_test.js
  61. 19
      src/node/test/surface_test.js
  62. 73
      templates/vsprojects/Grpc.mak.template
  63. 42
      templates/vsprojects/build_test_protos.sh
  64. 48
      templates/vsprojects/generate_debug_projects.sh
  65. 9
      templates/vsprojects/sln_defs.include
  66. 27
      templates/vsprojects/vcxproj_defs.include
  67. 124
      test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
  68. 54
      test/core/end2end/gen_build_json.py
  69. 123
      test/core/end2end/tests/channel_connectivity.c
  70. 5
      test/core/end2end/tests/disappearing_server.c
  71. 7
      test/core/end2end/tests/simple_delayed_request.c
  72. 2
      test/core/security/oauth2_utils.c
  73. 2
      test/cpp/client/credentials_test.cc
  74. 2
      test/cpp/end2end/end2end_test.cc
  75. 76
      tools/buildgen/generate_projects-old.sh
  76. 2
      tools/buildgen/plugins/generate_vsprojects.py
  77. 1
      tools/doxygen/Doxyfile.core.internal
  78. 4
      tools/gce_setup/cloud_prod_runner.sh
  79. 7
      tools/gce_setup/grpc_docker.sh
  80. 2
      tools/gce_setup/interop_test_runner.sh
  81. 15
      tools/jenkins/run_jenkins.sh
  82. 2
      tools/run_tests/jobset.py
  83. 36
      tools/run_tests/run_interops.py
  84. 47
      tools/run_tests/run_interops_build.sh
  85. 43
      tools/run_tests/run_interops_test.sh
  86. 4
      tools/run_tests/run_tests.py
  87. 2458
      tools/run_tests/sources_and_headers.json
  88. 1359
      tools/run_tests/tests.json
  89. 141
      vsprojects/Grpc.mak
  90. 65
      vsprojects/README.md
  91. 18
      vsprojects/cpptest.props
  92. 6
      vsprojects/global.props
  93. 2
      vsprojects/grpc/grpc.vcxproj
  94. 3
      vsprojects/grpc/grpc.vcxproj.filters
  95. 2
      vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
  96. 3
      vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
  97. 5
      vsprojects/make.bat

@ -343,6 +343,7 @@ cc_library(
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -578,6 +579,7 @@ cc_library(
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -1061,6 +1063,7 @@ objc_library(
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",

1749
Makefile

File diff suppressed because one or more lines are too long

@ -284,6 +284,7 @@
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -1894,6 +1895,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -1911,6 +1915,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -1969,6 +1976,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2207,6 +2217,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2225,6 +2238,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2239,6 +2255,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2343,6 +2362,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2361,6 +2383,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2379,6 +2404,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2430,6 +2458,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2479,6 +2510,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2496,6 +2530,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{

@ -352,6 +352,7 @@ Pod::Spec.new do |s|
'src/core/surface/call_details.c',
'src/core/surface/call_log_batch.c',
'src/core/surface/channel.c',
'src/core/surface/channel_connectivity.c',
'src/core/surface/channel_create.c',
'src/core/surface/completion_queue.c',
'src/core/surface/event_string.c',

@ -41,6 +41,7 @@
#include <grpc++/thread_pool_interface.h>
#include <list>
#include <memory>
#include <queue>
namespace grpc {

@ -87,7 +87,7 @@ class condition_variable {
~condition_variable() { gpr_cv_destroy(&cv_); }
void wait(lock_guard<mutex> &mu) {
mu.locked = false;
gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME);
gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
mu.locked = true;
}
void notify_one() { gpr_cv_signal(&cv_); }

@ -46,6 +46,7 @@
struct gpr_timespec;
struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc {
@ -122,6 +123,8 @@ class ServerContext {
// functionality. Instead, use auth_context.
grpc::string peer() const;
const struct census_context* census_context() const;
private:
friend class ::grpc::testing::InteropContextInspector;
friend class ::grpc::Server;

@ -44,26 +44,30 @@
extern "C" {
#endif
/* Identify census functionality that can be enabled via census_initialize(). */
enum census_functions {
CENSUS_NONE = 0, /* Do not enable census. */
CENSUS_TRACING = 1, /* Enable census tracing. */
CENSUS_STATS = 2, /* Enable Census stats collection. */
CENSUS_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_ALL = CENSUS_TRACING | CENSUS_STATS | CENSUS_CPU
/* Identify census features that can be enabled via census_initialize(). */
enum census_features {
CENSUS_FEATURE_NONE = 0, /* Do not enable census. */
CENSUS_FEATURE_TRACING = 1, /* Enable census tracing. */
CENSUS_FEATURE_STATS = 2, /* Enable Census stats collection. */
CENSUS_FEATURE_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_FEATURE_ALL =
CENSUS_FEATURE_TRACING | CENSUS_FEATURE_STATS | CENSUS_FEATURE_CPU
};
/* Shutdown and startup census subsystem. The 'functions' argument should be
* the OR (|) of census_functions values. If census fails to initialize, then
/** Shutdown and startup census subsystem. The 'features' argument should be
* the OR (|) of census_features values. If census fails to initialize, then
* census_initialize() will return a non-zero value. It is an error to call
* census_initialize() more than once (without an intervening
* census_shutdown()). */
int census_initialize(int functions);
void census_shutdown();
int census_initialize(int features);
void census_shutdown(void);
/* If any census feature has been initialized, this funtion will return a
* non-zero value. */
int census_available();
/** Return the features supported by the current census implementation (not all
* features will be available on all platforms). */
int census_supported(void);
/** Return the census features currently enabled. */
int census_enabled(void);
/* Internally, Census relies on a context, which should be propagated across
* RPC's. From the RPC subsystems viewpoint, this is an opaque data structure.

@ -402,6 +402,23 @@ 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);
/** Check the connectivity state of a channel. */
grpc_connectivity_state grpc_channel_check_connectivity_state(
grpc_channel *channel, int try_to_connect);
/** Watch for a change in connectivity state.
Once the channel connectivity state is different from last_observed_state,
tag will be enqueued on cq with success=1.
If deadline expires BEFORE the state is changed, tag will be enqueued on cq
with success=0.
If optional_new_state is non-NULL, it will be set to the newly observed
connectivity state of the channel at the same point as tag is enqueued onto
the completion queue. */
void grpc_channel_watch_connectivity_state(
grpc_channel *channel, grpc_connectivity_state last_observed_state,
grpc_connectivity_state *optional_new_state, gpr_timespec deadline,
grpc_completion_queue *cq, void *tag);
/** 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. */
@ -436,7 +453,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
/** Returns a newly allocated string representing the endpoint to which this
call is communicating with. The string is in the uri format accepted by
grpc_channel_create.
The returned string should be disposed of with gpr_free().
The returned string should be disposed of with gpr_free().
WARNING: this value is never authenticated or subject to any security
related code. It must not be used for any authentication related

@ -298,11 +298,13 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
out->Print("$returntype$ $methodname$($request$$response_stream_maybe$, ServerCallContext context);\n",
"methodname", method->name(), "returntype",
GetMethodReturnTypeServer(method), "request",
GetMethodRequestParamServer(method), "response_stream_maybe",
GetMethodResponseStreamMaybe(method));
out->Print(
"$returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context);\n",
"methodname", method->name(), "returntype",
GetMethodReturnTypeServer(method), "request",
GetMethodRequestParamServer(method), "response_stream_maybe",
GetMethodResponseStreamMaybe(method));
}
out->Outdent();
out->Print("}\n");

@ -39,7 +39,7 @@ static void grpc_census_context_destroy(void *context) {
}
void grpc_census_call_set_context(grpc_call *call, census_context *context) {
if (!census_available()) {
if (census_enabled() == CENSUS_FEATURE_NONE) {
return;
}
if (context == NULL) {

@ -33,20 +33,25 @@
#include <grpc/census.h>
static int census_fns_enabled = CENSUS_NONE;
static int features_enabled = CENSUS_FEATURE_NONE;
int census_initialize(int functions) {
if (census_fns_enabled != CENSUS_NONE) {
int census_initialize(int features) {
if (features_enabled != CENSUS_FEATURE_NONE) {
return 1;
}
if (functions != CENSUS_NONE) {
if (features != CENSUS_FEATURE_NONE) {
return 1;
} else {
census_fns_enabled = functions;
features_enabled = features;
return 0;
}
}
void census_shutdown() { census_fns_enabled = CENSUS_NONE; }
void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; }
int census_available() { return (census_fns_enabled != CENSUS_NONE); }
int census_supported(void) {
/* TODO(aveitch): improve this as we implement features... */
return CENSUS_FEATURE_NONE;
}
int census_enabled(void) { return features_enabled; }

@ -40,7 +40,6 @@
#include "src/core/channel/connected_channel.h"
#include "src/core/surface/channel.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/pollset_set.h"
#include "src/core/support/string.h"
#include "src/core/transport/connectivity_state.h"
#include <grpc/support/alloc.h>
@ -77,8 +76,22 @@ typedef struct {
grpc_iomgr_closure on_config_changed;
/** connectivity state being tracked */
grpc_connectivity_state_tracker state_tracker;
/** when an lb_policy arrives, should we try to exit idle */
int exit_idle_when_lb_policy_arrives;
/** pollset_set of interested parties in a new connection */
grpc_pollset_set pollset_set;
} channel_data;
/** We create one watcher for each new lb_policy that is returned from a resolver,
to watch for state changes from the lb_policy. When a state change is seen, we
update the channel, and create a new watcher */
typedef struct {
channel_data *chand;
grpc_iomgr_closure on_changed;
grpc_connectivity_state state;
grpc_lb_policy *lb_policy;
} lb_policy_connectivity_watcher;
typedef enum {
CALL_CREATED,
CALL_WAITING_FOR_SEND,
@ -408,16 +421,53 @@ static void cc_start_transport_stream_op(grpc_call_element *elem,
perform_transport_stream_op(elem, op, 0);
}
static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state);
static void on_lb_policy_state_changed(void *arg, int iomgr_success) {
lb_policy_connectivity_watcher *w = arg;
gpr_mu_lock(&w->chand->mu_config);
/* check if the notification is for a stale policy */
if (w->lb_policy == w->chand->lb_policy) {
grpc_connectivity_state_set(&w->chand->state_tracker, w->state,
"lb_changed");
if (w->state != GRPC_CHANNEL_FATAL_FAILURE) {
watch_lb_policy(w->chand, w->lb_policy, w->state);
}
}
gpr_mu_unlock(&w->chand->mu_config);
GRPC_CHANNEL_INTERNAL_UNREF(w->chand->master, "watch_lb_policy");
gpr_free(w);
}
static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state) {
lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy");
w->chand = chand;
grpc_iomgr_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
w->state = current_state;
w->lb_policy = lb_policy;
grpc_lb_policy_notify_on_state_change(lb_policy, &w->state, &w->on_changed);
}
static void cc_on_config_changed(void *arg, int iomgr_success) {
channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
grpc_resolver *old_resolver;
grpc_iomgr_closure *wakeup_closures = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
int exit_idle = 0;
if (chand->incoming_configuration != NULL) {
lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
GRPC_LB_POLICY_REF(lb_policy, "channel");
if (lb_policy != NULL) {
GRPC_LB_POLICY_REF(lb_policy, "channel");
GRPC_LB_POLICY_REF(lb_policy, "config_change");
state = grpc_lb_policy_check_connectivity(lb_policy);
}
grpc_client_config_unref(chand->incoming_configuration);
}
@ -431,13 +481,12 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
wakeup_closures = chand->waiting_for_config_closures;
chand->waiting_for_config_closures = NULL;
}
gpr_mu_unlock(&chand->mu_config);
if (old_lb_policy) {
GRPC_LB_POLICY_UNREF(old_lb_policy, "channel");
if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
exit_idle = 1;
chand->exit_idle_when_lb_policy_arrives = 0;
}
gpr_mu_lock(&chand->mu_config);
if (iomgr_success && chand->resolver) {
grpc_resolver *resolver = chand->resolver;
GRPC_RESOLVER_REF(resolver, "channel-next");
@ -446,11 +495,16 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
GRPC_RESOLVER_UNREF(resolver, "channel-next");
grpc_connectivity_state_set(&chand->state_tracker, state,
"new_lb+resolver");
if (lb_policy != NULL) {
watch_lb_policy(chand, lb_policy, state);
}
} else {
old_resolver = chand->resolver;
chand->resolver = NULL;
grpc_connectivity_state_set(&chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE);
GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone");
gpr_mu_unlock(&chand->mu_config);
if (old_resolver != NULL) {
grpc_resolver_shutdown(old_resolver);
@ -458,12 +512,24 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
}
}
if (exit_idle) {
grpc_lb_policy_exit_idle(lb_policy);
GRPC_LB_POLICY_UNREF(lb_policy, "exit_idle");
}
if (old_lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(old_lb_policy, "channel");
}
while (wakeup_closures) {
grpc_iomgr_closure *next = wakeup_closures->next;
wakeup_closures->cb(wakeup_closures->cb_arg, 1);
wakeup_closures = next;
}
if (lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(lb_policy, "config_change");
}
GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver");
}
@ -487,20 +553,22 @@ static void cc_start_transport_op(grpc_channel_element *elem,
op->connectivity_state = NULL;
}
if (!is_empty(op, sizeof(*op))) {
lb_policy = chand->lb_policy;
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "broadcast");
}
}
if (op->disconnect && chand->resolver != NULL) {
grpc_connectivity_state_set(&chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE);
GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
destroy_resolver = chand->resolver;
chand->resolver = NULL;
if (chand->lb_policy != NULL) {
grpc_lb_policy_shutdown(chand->lb_policy);
}
}
if (!is_empty(op, sizeof(*op))) {
lb_policy = chand->lb_policy;
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "broadcast");
GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
chand->lb_policy = NULL;
}
}
gpr_mu_unlock(&chand->mu_config);
@ -581,10 +649,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
gpr_mu_init(&chand->mu_config);
chand->mdctx = metadata_context;
chand->master = master;
grpc_pollset_set_init(&chand->pollset_set);
grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed,
chand);
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE);
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel");
}
/* Destructor for channel_data */
@ -598,6 +667,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
if (chand->lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
}
grpc_connectivity_state_destroy(&chand->state_tracker);
grpc_pollset_set_destroy(&chand->pollset_set);
gpr_mu_destroy(&chand->mu_config);
}
@ -626,3 +697,47 @@ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
}
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element *elem, int try_to_connect) {
channel_data *chand = elem->channel_data;
grpc_connectivity_state out;
gpr_mu_lock(&chand->mu_config);
out = grpc_connectivity_state_check(&chand->state_tracker);
if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
if (chand->lb_policy != NULL) {
grpc_lb_policy_exit_idle(chand->lb_policy);
} else {
chand->exit_idle_when_lb_policy_arrives = 1;
}
}
gpr_mu_unlock(&chand->mu_config);
return out;
}
void grpc_client_channel_watch_connectivity_state(
grpc_channel_element *elem, grpc_connectivity_state *state,
grpc_iomgr_closure *on_complete) {
channel_data *chand = elem->channel_data;
gpr_mu_lock(&chand->mu_config);
grpc_connectivity_state_notify_on_state_change(&chand->state_tracker, state,
on_complete);
gpr_mu_unlock(&chand->mu_config);
}
grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
return &chand->pollset_set;
}
void grpc_client_channel_add_interested_party(grpc_channel_element *elem,
grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_add_pollset(&chand->pollset_set, pollset);
}
void grpc_client_channel_del_interested_party(grpc_channel_element *elem,
grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_del_pollset(&chand->pollset_set, pollset);
}

@ -52,4 +52,18 @@ extern const grpc_channel_filter grpc_client_channel_filter;
void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
grpc_resolver *resolver);
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element *elem, int try_to_connect);
void grpc_client_channel_watch_connectivity_state(
grpc_channel_element *elem, grpc_connectivity_state *state,
grpc_iomgr_closure *on_complete);
grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem);
void grpc_client_channel_add_interested_party(grpc_channel_element *channel,
grpc_pollset *pollset);
void grpc_client_channel_del_interested_party(grpc_channel_element *channel,
grpc_pollset *pollset);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */

@ -62,6 +62,8 @@ typedef struct {
grpc_subchannel *selected;
/** have we started picking? */
int started_picking;
/** are we shut down? */
int shutdown;
/** which subchannel are we watching? */
size_t checking_subchannel;
/** what is the connectivity of that channel? */
@ -73,12 +75,30 @@ typedef struct {
grpc_connectivity_state_tracker state_tracker;
} pick_first_lb_policy;
static void del_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
static void add_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
void pf_destroy(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i;
del_interested_parties_locked(p);
for (i = 0; i < p->num_subchannels; i++) {
GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first");
}
grpc_connectivity_state_destroy(&p->state_tracker);
gpr_free(p->subchannels);
gpr_mu_destroy(&p->mu);
gpr_free(p);
@ -88,12 +108,35 @@ void pf_shutdown(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
del_interested_parties_locked(p);
p->shutdown = 1;
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_iomgr_add_delayed_callback(pp->on_complete, 0);
gpr_free(pp);
}
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_FATAL_FAILURE,
"shutdown");
gpr_mu_unlock(&p->mu);
}
static void start_picking(pick_first_lb_policy *p) {
p->started_picking = 1;
p->checking_subchannel = 0;
p->checking_connectivity = GRPC_CHANNEL_IDLE;
GRPC_LB_POLICY_REF(&p->base, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change(p->subchannels[p->checking_subchannel],
&p->checking_connectivity,
&p->connectivity_changed);
}
void pf_exit_idle(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
gpr_mu_lock(&p->mu);
if (!p->started_picking) {
start_picking(p);
}
gpr_mu_unlock(&p->mu);
}
@ -109,13 +152,7 @@ void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
on_complete->cb(on_complete->cb_arg, 1);
} else {
if (!p->started_picking) {
p->started_picking = 1;
p->checking_subchannel = 0;
p->checking_connectivity = GRPC_CHANNEL_IDLE;
GRPC_LB_POLICY_REF(pol, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
start_picking(p);
}
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pollset);
@ -129,77 +166,97 @@ void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
}
}
static void del_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
static void add_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
static void pf_connectivity_changed(void *arg, int iomgr_success) {
pick_first_lb_policy *p = arg;
pending_pick *pp;
int unref = 0;
gpr_mu_lock(&p->mu);
loop:
switch (p->checking_connectivity) {
case GRPC_CHANNEL_READY:
p->selected = p->subchannels[p->checking_subchannel];
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = p->selected;
grpc_subchannel_del_interested_party(p->selected, pp->pollset);
grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
del_interested_parties_locked(p);
p->checking_subchannel =
(p->checking_subchannel + 1) % p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(p);
goto loop;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
if (p->shutdown) {
unref = 1;
} else if (p->selected != NULL) {
grpc_connectivity_state_set(&p->state_tracker, p->checking_connectivity,
"selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
break;
case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(p);
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first");
if (p->num_subchannels == 0) {
p->selected, &p->checking_connectivity, &p->connectivity_changed);
} else {
unref = 1;
}
} else {
loop:
switch (p->checking_connectivity) {
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY,
"connecting_ready");
p->selected = p->subchannels[p->checking_subchannel];
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
*pp->target = p->selected;
grpc_subchannel_del_interested_party(p->selected, pp->pollset);
grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
} else {
p->checking_subchannel %= p->num_subchannels;
grpc_subchannel_notify_on_state_change(
p->selected, &p->checking_connectivity, &p->connectivity_changed);
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure");
del_interested_parties_locked(p);
p->checking_subchannel =
(p->checking_subchannel + 1) % p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(p);
goto loop;
}
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
} else {
goto loop;
}
break;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(&p->state_tracker, p->checking_connectivity,
"connecting_changed");
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
break;
case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(p);
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first");
if (p->num_subchannels == 0) {
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE,
"no_more_channels");
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
} else {
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"subchannel_failed");
p->checking_subchannel %= p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(p);
goto loop;
}
}
}
gpr_mu_unlock(&p->mu);
if (unref) {
@ -249,8 +306,13 @@ static void pf_notify_on_state_change(grpc_lb_policy *pol,
}
static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
pf_destroy, pf_shutdown, pf_pick,
pf_broadcast, pf_check_connectivity, pf_notify_on_state_change};
pf_destroy,
pf_shutdown,
pf_pick,
pf_exit_idle,
pf_broadcast,
pf_check_connectivity,
pf_notify_on_state_change};
grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
size_t num_subchannels) {
@ -260,6 +322,8 @@ grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_subchannels);
p->num_subchannels = num_subchannels;
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"pick_first");
memcpy(p->subchannels, subchannels,
sizeof(grpc_subchannel *) * num_subchannels);
grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);

@ -77,3 +77,18 @@ void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op) {
policy->vtable->broadcast(policy, op);
}
void grpc_lb_policy_exit_idle(grpc_lb_policy *policy) {
policy->vtable->exit_idle(policy);
}
void grpc_lb_policy_notify_on_state_change(grpc_lb_policy *policy,
grpc_connectivity_state *state,
grpc_iomgr_closure *closure) {
policy->vtable->notify_on_state_change(policy, state, closure);
}
grpc_connectivity_state grpc_lb_policy_check_connectivity(
grpc_lb_policy *policy) {
return policy->vtable->check_connectivity(policy);
}

@ -59,6 +59,9 @@ struct grpc_lb_policy_vtable {
grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
grpc_iomgr_closure *on_complete);
/** try to enter a READY connectivity state */
void (*exit_idle)(grpc_lb_policy *policy);
/** broadcast a transport op to all subchannels */
void (*broadcast)(grpc_lb_policy *policy, grpc_transport_op *op);
@ -106,4 +109,13 @@ void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op);
void grpc_lb_policy_exit_idle(grpc_lb_policy *policy);
void grpc_lb_policy_notify_on_state_change(grpc_lb_policy *policy,
grpc_connectivity_state *state,
grpc_iomgr_closure *closure);
grpc_connectivity_state grpc_lb_policy_check_connectivity(
grpc_lb_policy *policy);
#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */

@ -38,9 +38,11 @@
#include <grpc/support/alloc.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/client_channel.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/transport/connectivity_state.h"
#include "src/core/surface/channel.h"
typedef struct {
/* all fields protected by subchannel->mu */
@ -94,8 +96,10 @@ struct grpc_subchannel {
grpc_iomgr_closure connected;
/** pollset_set tracking who's interested in a connection
being setup */
grpc_pollset_set pollset_set;
being setup - owned by the master channel (in particular the
client_channel
filter there-in) */
grpc_pollset_set *pollset_set;
/** mutex protecting remaining elements */
gpr_mu mu;
@ -132,7 +136,8 @@ struct grpc_subchannel_call {
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1))
static grpc_subchannel_call *create_call(connection *con);
static void connectivity_state_changed_locked(grpc_subchannel *c);
static void connectivity_state_changed_locked(grpc_subchannel *c,
const char *reason);
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c);
static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
static void subchannel_connected(void *subchannel, int iomgr_success);
@ -244,7 +249,6 @@ static void subchannel_destroy(grpc_subchannel *c) {
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
grpc_mdctx_unref(c->mdctx);
grpc_pollset_set_destroy(&c->pollset_set);
grpc_connectivity_state_destroy(&c->state_tracker);
grpc_connector_unref(c->connector);
gpr_free(c);
@ -252,17 +256,19 @@ static void subchannel_destroy(grpc_subchannel *c) {
void grpc_subchannel_add_interested_party(grpc_subchannel *c,
grpc_pollset *pollset) {
grpc_pollset_set_add_pollset(&c->pollset_set, pollset);
grpc_pollset_set_add_pollset(c->pollset_set, pollset);
}
void grpc_subchannel_del_interested_party(grpc_subchannel *c,
grpc_pollset *pollset) {
grpc_pollset_set_del_pollset(&c->pollset_set, pollset);
grpc_pollset_set_del_pollset(c->pollset_set, pollset);
}
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args) {
grpc_subchannel *c = gpr_malloc(sizeof(*c));
grpc_channel_element *parent_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(args->master));
memset(c, 0, sizeof(*c));
c->refs = 1;
c->connector = connector;
@ -277,10 +283,11 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
c->args = grpc_channel_args_copy(args->args);
c->mdctx = args->mdctx;
c->master = args->master;
c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem);
grpc_mdctx_ref(c->mdctx);
grpc_pollset_set_init(&c->pollset_set);
grpc_iomgr_closure_init(&c->connected, subchannel_connected, c);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel");
gpr_mu_init(&c->mu);
return c;
}
@ -288,7 +295,7 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
static void continue_connect(grpc_subchannel *c) {
grpc_connect_in_args args;
args.interested_parties = &c->pollset_set;
args.interested_parties = c->pollset_set;
args.addr = c->addr;
args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c);
@ -309,6 +316,7 @@ static void start_connect(grpc_subchannel *c) {
static void continue_creating_call(void *arg, int iomgr_success) {
waiting_for_connect *w4c = arg;
grpc_subchannel_del_interested_party(w4c->subchannel, w4c->pollset);
grpc_subchannel_create_call(w4c->subchannel, w4c->pollset, w4c->target,
w4c->notify);
GRPC_SUBCHANNEL_UNREF(w4c->subchannel, "waiting_for_connect");
@ -341,9 +349,10 @@ void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset,
grpc_subchannel_add_interested_party(c, pollset);
if (!c->connecting) {
c->connecting = 1;
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "create_call");
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
gpr_mu_unlock(&c->mu);
start_connect(c);
@ -372,7 +381,8 @@ void grpc_subchannel_notify_on_state_change(grpc_subchannel *c,
c->connecting = 1;
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
connectivity_state_changed_locked(c);
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
connectivity_state_changed_locked(c, "state_change");
}
gpr_mu_unlock(&c->mu);
if (do_connect) {
@ -388,7 +398,7 @@ void grpc_subchannel_process_transport_op(grpc_subchannel *c,
gpr_mu_lock(&c->mu);
if (op->disconnect) {
c->disconnected = 1;
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "disconnect");
if (c->have_alarm) {
cancel_alarm = 1;
}
@ -456,13 +466,15 @@ static void on_state_changed(void *p, int iomgr_success) {
destroy_connection = sw->subchannel->active;
}
sw->subchannel->active = NULL;
grpc_connectivity_state_set(&c->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE);
grpc_connectivity_state_set(
&c->state_tracker, c->disconnected ? GRPC_CHANNEL_FATAL_FAILURE
: GRPC_CHANNEL_TRANSIENT_FAILURE,
"connection_failed");
break;
}
done:
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "transport_state_changed");
destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher");
gpr_free(sw);
gpr_mu_unlock(mu);
@ -486,6 +498,8 @@ static void publish_transport(grpc_subchannel *c) {
connection *destroy_connection = NULL;
grpc_channel_element *elem;
gpr_log(GPR_DEBUG, "publish_transport: %p", c->master);
/* build final filter list */
num_filters = c->num_filters + c->connecting_result.num_filters + 1;
filters = gpr_malloc(sizeof(*filters) * num_filters);
@ -519,6 +533,8 @@ static void publish_transport(grpc_subchannel *c) {
gpr_free(sw);
gpr_free(filters);
grpc_channel_stack_destroy(stk);
GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
GRPC_SUBCHANNEL_UNREF(c, "connecting");
return;
}
@ -536,14 +552,16 @@ static void publish_transport(grpc_subchannel *c) {
memset(&op, 0, sizeof(op));
op.connectivity_state = &sw->connectivity_state;
op.on_connectivity_state_change = &sw->closure;
op.bind_pollset_set = c->pollset_set;
SUBCHANNEL_REF_LOCKED(c, "state_watcher");
GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting"));
elem =
grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
elem->filter->start_transport_op(elem, &op);
/* signal completion */
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "connected");
while ((w4c = c->waiting)) {
c->waiting = w4c->next;
grpc_iomgr_add_callback(&w4c->continuation);
@ -565,11 +583,12 @@ static void on_alarm(void *arg, int iomgr_success) {
if (c->disconnected) {
iomgr_success = 0;
}
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "alarm");
gpr_mu_unlock(&c->mu);
if (iomgr_success) {
continue_connect(c);
} else {
GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
GRPC_SUBCHANNEL_UNREF(c, "connecting");
}
}
@ -579,13 +598,17 @@ static void subchannel_connected(void *arg, int iomgr_success) {
if (c->connecting_result.transport != NULL) {
publish_transport(c);
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_mu_lock(&c->mu);
connectivity_state_changed_locked(c);
GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1;
connectivity_state_changed_locked(c, "connect_failed");
c->next_attempt = gpr_time_add(c->next_attempt, c->backoff_delta);
c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta);
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now(GPR_CLOCK_MONOTONIC));
if (gpr_time_cmp(c->backoff_delta,
gpr_time_from_seconds(60, GPR_TIMESPAN)) < 0) {
c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta);
}
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, now);
gpr_mu_unlock(&c->mu);
}
}
@ -610,9 +633,10 @@ static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
return GRPC_CHANNEL_IDLE;
}
static void connectivity_state_changed_locked(grpc_subchannel *c) {
static void connectivity_state_changed_locked(grpc_subchannel *c,
const char *reason) {
grpc_connectivity_state current = compute_connectivity_locked(c);
grpc_connectivity_state_set(&c->state_tracker, current);
grpc_connectivity_state_set(&c->state_tracker, current, reason);
}
/*

@ -361,7 +361,9 @@ static int run_some_expired_alarms(gpr_mu *drop_mu, gpr_timespec now,
int grpc_alarm_check(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next) {
GPR_ASSERT(now.clock_type == g_clock_type);
return run_some_expired_alarms(drop_mu, now, next, 1);
return run_some_expired_alarms(
drop_mu, now, next,
gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
}
gpr_timespec grpc_alarm_list_next_timeout(void) {

@ -50,6 +50,10 @@ void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
ep->vtable->add_to_pollset(ep, pollset);
}
void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) {
ep->vtable->add_to_pollset_set(ep, pollset_set);
}
void grpc_endpoint_shutdown(grpc_endpoint *ep) { ep->vtable->shutdown(ep); }
void grpc_endpoint_destroy(grpc_endpoint *ep) { ep->vtable->destroy(ep); }

@ -35,6 +35,7 @@
#define GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H
#include "src/core/iomgr/pollset.h"
#include "src/core/iomgr/pollset_set.h"
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
@ -70,6 +71,7 @@ struct grpc_endpoint_vtable {
size_t nslices, grpc_endpoint_write_cb cb,
void *user_data);
void (*add_to_pollset)(grpc_endpoint *ep, grpc_pollset *pollset);
void (*add_to_pollset_set)(grpc_endpoint *ep, grpc_pollset_set *pollset);
void (*shutdown)(grpc_endpoint *ep);
void (*destroy)(grpc_endpoint *ep);
char *(*get_peer)(grpc_endpoint *ep);
@ -101,6 +103,7 @@ void grpc_endpoint_destroy(grpc_endpoint *ep);
/* Add an endpoint to a pollset, so that when the pollset is polled, events from
this endpoint are considered */
void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset);
void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set);
struct grpc_endpoint {
const grpc_endpoint_vtable *vtable;

@ -81,8 +81,10 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read
SOCKET sv[2];
grpc_endpoint_pair p;
create_sockets(sv);
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"), "endpoint:server");
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"), "endpoint:client");
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
"endpoint:server");
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
"endpoint:client");
return p;
}

@ -147,7 +147,6 @@ void grpc_iomgr_shutdown(void) {
continue;
}
if (grpc_alarm_check(&g_mu, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL)) {
gpr_log(GPR_DEBUG, "got late alarm");
continue;
}
if (g_root_object.next != &g_root_object) {

@ -60,7 +60,7 @@ void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
grpc_pollset *pollset) {
size_t i;
size_t i, j;
gpr_mu_lock(&pollset_set->mu);
if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
pollset_set->pollset_capacity =
@ -70,9 +70,15 @@ void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
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]);
for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
if (grpc_fd_is_orphaned(pollset_set->fds[i])) {
GRPC_FD_UNREF(pollset_set->fds[i], "pollset");
} else {
grpc_pollset_add_fd(pollset, pollset_set->fds[i]);
pollset_set->fds[j++] = pollset_set->fds[i];
}
}
pollset_set->fd_count = j;
gpr_mu_unlock(&pollset_set->mu);
}

@ -89,11 +89,11 @@ error:
return 0;
}
static void on_alarm(void *acp, int success) {
static void tc_on_alarm(void *acp, int success) {
int done;
async_connect *ac = acp;
gpr_mu_lock(&ac->mu);
if (ac->fd != NULL && success) {
if (ac->fd != NULL) {
grpc_fd_shutdown(ac->fd);
}
done = (--ac->refs == 0);
@ -110,11 +110,17 @@ static void on_writable(void *acp, int success) {
int so_error = 0;
socklen_t so_error_size;
int err;
int fd = ac->fd->fd;
int done;
grpc_endpoint *ep = NULL;
void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
void *cb_arg = ac->cb_arg;
grpc_fd *fd;
gpr_mu_lock(&ac->mu);
GPR_ASSERT(ac->fd);
fd = ac->fd;
ac->fd = NULL;
gpr_mu_unlock(&ac->mu);
grpc_alarm_cancel(&ac->alarm);
@ -122,7 +128,7 @@ static void on_writable(void *acp, int success) {
if (success) {
do {
so_error_size = sizeof(so_error);
err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
} while (err < 0 && errno == EINTR);
if (err < 0) {
gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno));
@ -145,7 +151,7 @@ static void on_writable(void *acp, int success) {
don't do that! */
gpr_log(GPR_ERROR, "kernel out of buffers");
gpr_mu_unlock(&ac->mu);
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
grpc_fd_notify_on_write(fd, &ac->write_closure);
return;
} else {
switch (so_error) {
@ -159,9 +165,9 @@ static void on_writable(void *acp, int success) {
goto finish;
}
} else {
grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
ep = grpc_tcp_create(ac->fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE,
ac->addr_str);
grpc_pollset_set_del_fd(ac->interested_parties, fd);
ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str);
fd = NULL;
goto finish;
}
} else {
@ -172,11 +178,10 @@ static void on_writable(void *acp, int success) {
abort();
finish:
if (ep == NULL) {
grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
} else {
ac->fd = NULL;
if (fd != NULL) {
grpc_pollset_set_del_fd(ac->interested_parties, fd);
grpc_fd_orphan(fd, NULL, "tcp_client_orphan");
fd = NULL;
}
done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
@ -260,7 +265,7 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
gpr_mu_lock(&ac->mu);
grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
gpr_mu_unlock(&ac->mu);

@ -572,14 +572,21 @@ static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
grpc_pollset_add_fd(pollset, tcp->em_fd);
}
static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_pollset_set_add_fd(pollset_set, tcp->em_fd);
}
static char *grpc_tcp_get_peer(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
return gpr_strdup(tcp->peer_string);
}
static const grpc_endpoint_vtable vtable = {
grpc_tcp_notify_on_read, grpc_tcp_write, grpc_tcp_add_to_pollset,
grpc_tcp_shutdown, grpc_tcp_destroy, grpc_tcp_get_peer};
grpc_tcp_notify_on_read, grpc_tcp_write,
grpc_tcp_add_to_pollset, grpc_tcp_add_to_pollset_set,
grpc_tcp_shutdown, grpc_tcp_destroy,
grpc_tcp_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
const char *peer_string) {

@ -79,6 +79,8 @@ struct grpc_tcp_server {
/* active port count: how many ports are actually still listening */
int active_ports;
/* number of iomgr callbacks that have been explicitly scheduled during shutdown */
int iomgr_callbacks_pending;
/* all listening ports */
server_port *ports;
@ -93,6 +95,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
gpr_mu_init(&s->mu);
gpr_cv_init(&s->cv);
s->active_ports = 0;
s->iomgr_callbacks_pending = 0;
s->cb = NULL;
s->cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
@ -112,10 +115,10 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s,
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
sp->shutting_down = 1;
grpc_winsocket_shutdown(sp->socket);
s->iomgr_callbacks_pending += grpc_winsocket_shutdown(sp->socket);
}
/* This happens asynchronously. Wait while that happens. */
while (s->active_ports) {
while (s->active_ports || s->iomgr_callbacks_pending) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
}
gpr_mu_unlock(&s->mu);
@ -254,8 +257,16 @@ static void on_accept(void *arg, int from_iocp) {
/* The general mechanism for shutting down is to queue abortion calls. While
this is necessary in the read/write case, it's useless for the accept
case. Let's do nothing. */
if (!from_iocp) return;
case. We only need to adjust the pending callback count */
if (!from_iocp) {
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->iomgr_callbacks_pending > 0);
if (0 == --sp->server->iomgr_callbacks_pending) {
gpr_cv_broadcast(&sp->server->cv);
}
gpr_mu_unlock(&sp->server->mu);
return;
}
/* The IOCP notified us of a completed operation. Let's grab the results,
and act accordingly. */
@ -264,11 +275,12 @@ static void on_accept(void *arg, int from_iocp) {
&transfered_bytes, FALSE, &flags);
if (!wsa_success) {
if (sp->shutting_down) {
/* During the shutdown case, we ARE expecting an error. So that's swell,
/* During the shutdown case, we ARE expecting an error. So that's well,
and we can wake up the shutdown thread. */
sp->shutting_down = 0;
sp->socket->read_info.outstanding = 0;
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->active_ports > 0);
if (0 == --sp->server->active_ports) {
gpr_cv_broadcast(&sp->server->cv);
}

@ -368,7 +368,14 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
return GRPC_ENDPOINT_WRITE_PENDING;
}
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) {
(void) ps;
grpc_tcp *tcp = (grpc_tcp *) ep;
grpc_iocp_add_socket(tcp->socket);
}
static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
(void) pss;
grpc_tcp *tcp = (grpc_tcp *) ep;
grpc_iocp_add_socket(tcp->socket);
}
@ -401,9 +408,10 @@ static char *win_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string);
}
static grpc_endpoint_vtable vtable = {
win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy, win_get_peer
};
static grpc_endpoint_vtable vtable = {win_notify_on_read, win_write,
win_add_to_pollset, win_add_to_pollset_set,
win_shutdown, win_destroy,
win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));

@ -331,14 +331,22 @@ static void endpoint_add_to_pollset(grpc_endpoint *secure_ep,
grpc_endpoint_add_to_pollset(ep->wrapped_ep, pollset);
}
static void endpoint_add_to_pollset_set(grpc_endpoint *secure_ep,
grpc_pollset_set *pollset_set) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
grpc_endpoint_add_to_pollset_set(ep->wrapped_ep, pollset_set);
}
static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
return grpc_endpoint_get_peer(ep->wrapped_ep);
}
static const grpc_endpoint_vtable vtable = {
endpoint_notify_on_read, endpoint_write, endpoint_add_to_pollset,
endpoint_shutdown, endpoint_unref, endpoint_get_peer};
endpoint_notify_on_read, endpoint_write,
endpoint_add_to_pollset, endpoint_add_to_pollset_set,
endpoint_shutdown, endpoint_unref,
endpoint_get_peer};
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *transport,

@ -72,6 +72,11 @@ typedef union lockfree_node {
struct gpr_stack_lockfree {
lockfree_node *entries;
lockfree_node head; /* An atomic entry describing curr head */
#ifndef NDEBUG
/* Bitmap of pushed entries to check for double-push or pop */
gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))];
#endif
};
gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
@ -86,6 +91,9 @@ gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
/* Clear out all entries */
memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
memset(&stack->head, 0, sizeof(stack->head));
#ifndef NDEBUG
memset(&stack->pushed, 0, sizeof(stack->pushed));
#endif
/* Point the head at reserved dummy entry */
stack->head.contents.index = INVALID_ENTRY_INDEX;
@ -106,6 +114,19 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
/* Also post-increment the aba_ctr */
newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++;
#ifndef NDEBUG
/* Check for double push */
{
int pushed_index = entry / (8*sizeof(gpr_atm));
int pushed_bit = entry % (8*sizeof(gpr_atm));
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
(gpr_atm)(1UL << pushed_bit));
GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0);
}
#endif
do {
/* Atomically get the existing head value for use */
head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
@ -119,6 +140,7 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
lockfree_node head;
lockfree_node newhead;
do {
head.atm = gpr_atm_acq_load(&(stack->head.atm));
if (head.contents.index == INVALID_ENTRY_INDEX) {
@ -128,5 +150,18 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
} while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
#ifndef NDEBUG
/* Check for valid pop */
{
int pushed_index = head.contents.index / (8*sizeof(gpr_atm));
int pushed_bit = head.contents.index % (8*sizeof(gpr_atm));
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
-(gpr_atm)(1UL << pushed_bit));
GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0);
}
#endif
return head.contents.index;
}

@ -0,0 +1,191 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/surface/channel.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/channel/client_channel.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/surface/completion_queue.h"
grpc_connectivity_state grpc_channel_check_connectivity_state(
grpc_channel *channel, int try_to_connect) {
/* forward through to the underlying client channel */
grpc_channel_element *client_channel_elem =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
if (client_channel_elem->filter != &grpc_client_channel_filter) {
gpr_log(GPR_ERROR,
"grpc_channel_check_connectivity_state called on something that is "
"not a client channel, but '%s'",
client_channel_elem->filter->name);
return GRPC_CHANNEL_FATAL_FAILURE;
}
return grpc_client_channel_check_connectivity_state(client_channel_elem,
try_to_connect);
}
typedef enum {
WAITING,
CALLING_BACK,
CALLING_BACK_AND_FINISHED,
CALLED_BACK
} callback_phase;
typedef struct {
gpr_mu mu;
callback_phase phase;
int success;
grpc_iomgr_closure on_complete;
grpc_alarm alarm;
grpc_connectivity_state state;
grpc_connectivity_state *optional_new_state;
grpc_completion_queue *cq;
grpc_cq_completion completion_storage;
grpc_channel *channel;
void *tag;
} state_watcher;
static void delete_state_watcher(state_watcher *w) {
grpc_channel_element *client_channel_elem =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(w->channel));
grpc_client_channel_del_interested_party(client_channel_elem, grpc_cq_pollset(w->cq));
GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity");
gpr_mu_destroy(&w->mu);
gpr_free(w);
}
static void finished_completion(void *pw, grpc_cq_completion *ignored) {
int delete = 0;
state_watcher *w = pw;
gpr_mu_lock(&w->mu);
switch (w->phase) {
case WAITING:
case CALLED_BACK:
gpr_log(GPR_ERROR, "should never reach here");
abort();
break;
case CALLING_BACK:
w->phase = CALLED_BACK;
break;
case CALLING_BACK_AND_FINISHED:
delete = 1;
break;
}
gpr_mu_unlock(&w->mu);
if (delete) {
delete_state_watcher(w);
}
}
static void partly_done(state_watcher *w, int due_to_completion) {
int delete = 0;
if (due_to_completion) {
gpr_mu_lock(&w->mu);
w->success = 1;
gpr_mu_unlock(&w->mu);
grpc_alarm_cancel(&w->alarm);
}
gpr_mu_lock(&w->mu);
switch (w->phase) {
case WAITING:
w->phase = CALLING_BACK;
if (w->optional_new_state) {
*w->optional_new_state = w->state;
}
grpc_cq_end_op(w->cq, w->tag, w->success, finished_completion, w,
&w->completion_storage);
break;
case CALLING_BACK:
w->phase = CALLING_BACK_AND_FINISHED;
break;
case CALLING_BACK_AND_FINISHED:
gpr_log(GPR_ERROR, "should never reach here");
abort();
break;
case CALLED_BACK:
delete = 1;
break;
}
gpr_mu_unlock(&w->mu);
if (delete) {
delete_state_watcher(w);
}
}
static void watch_complete(void *pw, int success) { partly_done(pw, 1); }
static void timeout_complete(void *pw, int success) { partly_done(pw, 0); }
void grpc_channel_watch_connectivity_state(
grpc_channel *channel, grpc_connectivity_state last_observed_state,
grpc_connectivity_state *optional_new_state, gpr_timespec deadline,
grpc_completion_queue *cq, void *tag) {
grpc_channel_element *client_channel_elem =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
state_watcher *w = gpr_malloc(sizeof(*w));
grpc_cq_begin_op(cq);
gpr_mu_init(&w->mu);
grpc_iomgr_closure_init(&w->on_complete, watch_complete, w);
w->phase = WAITING;
w->state = last_observed_state;
w->success = 0;
w->optional_new_state = optional_new_state;
w->cq = cq;
w->tag = tag;
w->channel = channel;
grpc_alarm_init(
&w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
if (client_channel_elem->filter != &grpc_client_channel_filter) {
gpr_log(GPR_ERROR,
"grpc_channel_watch_connectivity_state called on something that is "
"not a client channel, but '%s'",
client_channel_elem->filter->name);
grpc_iomgr_add_delayed_callback(&w->on_complete, 1);
} else {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_connectivity");
grpc_client_channel_add_interested_party(client_channel_elem, grpc_cq_pollset(cq));
grpc_client_channel_watch_connectivity_state(client_channel_elem, &w->state,
&w->on_complete);
}
}

@ -109,6 +109,7 @@ typedef struct {
gpr_refcount refs;
grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel *master;
} subchannel_factory;
static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
@ -119,6 +120,7 @@ static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
subchannel_factory *f = (subchannel_factory *)scf;
if (gpr_unref(&f->refs)) {
GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
grpc_mdctx_unref(f->mdctx);
gpr_free(f);
@ -137,6 +139,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
gpr_ref_init(&c->refs, 1);
args->mdctx = f->mdctx;
args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(&c->base);
grpc_channel_args_destroy(final_args);
@ -168,19 +171,22 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel =
grpc_channel_create_from_filters(target, filters, n, args, mdctx, 1);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
grpc_mdctx_ref(mdctx);
f->mdctx = mdctx;
f->merge_args = grpc_channel_args_copy(args);
f->master = channel;
GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");
resolver = grpc_resolver_create(target, &f->base);
if (!resolver) {
return NULL;
}
channel =
grpc_channel_create_from_filters(target, filters, n, args, mdctx, 1);
grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
resolver);
GRPC_RESOLVER_UNREF(resolver, "create");

@ -47,6 +47,7 @@
#include "src/core/surface/init.h"
#include "src/core/surface/surface_trace.h"
#include "src/core/transport/chttp2_transport.h"
#include "src/core/transport/connectivity_state.h"
static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu;
@ -75,11 +76,15 @@ void grpc_init(void) {
grpc_register_tracer("http", &grpc_http_trace);
grpc_register_tracer("flowctl", &grpc_flowctl_trace);
grpc_register_tracer("batch", &grpc_trace_batch);
grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace);
grpc_security_pre_init();
grpc_iomgr_init();
grpc_tracer_init("GRPC_TRACE");
if (census_initialize(CENSUS_NONE)) {
gpr_log(GPR_ERROR, "Could not initialize census.");
/* Only initialize census if noone else has. */
if (census_enabled() == CENSUS_FEATURE_NONE) {
if (census_initialize(census_supported())) { /* enable all features. */
gpr_log(GPR_ERROR, "Could not initialize census.");
}
}
grpc_timers_global_init();
}

@ -134,6 +134,7 @@ typedef struct {
grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel_security_connector *security_connector;
grpc_channel *master;
} subchannel_factory;
static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
@ -146,6 +147,7 @@ static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
if (gpr_unref(&f->refs)) {
GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
"subchannel_factory");
GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
grpc_mdctx_unref(f->mdctx);
gpr_free(f);
@ -165,6 +167,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
gpr_ref_init(&c->refs, 1);
args->mdctx = f->mdctx;
args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(&c->base);
grpc_channel_args_destroy(final_args);
@ -218,6 +221,9 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel =
grpc_channel_create_from_filters(target, filters, n, args_copy, mdctx, 1);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
@ -226,13 +232,13 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
GRPC_SECURITY_CONNECTOR_REF(&connector->base, "subchannel_factory");
f->security_connector = connector;
f->merge_args = grpc_channel_args_copy(args_copy);
f->master = channel;
GRPC_CHANNEL_INTERNAL_REF(channel, "subchannel_factory");
resolver = grpc_resolver_create(target, &f->base);
if (!resolver) {
return NULL;
}
channel =
grpc_channel_create_from_filters(target, filters, n, args_copy, mdctx, 1);
grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
resolver);
GRPC_RESOLVER_UNREF(resolver, "create");

@ -110,6 +110,8 @@ static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
/** Add endpoint from this transport to pollset */
static void add_to_pollset_locked(grpc_chttp2_transport *t,
grpc_pollset *pollset);
static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
grpc_pollset_set *pollset_set);
/** Start new streams that have been created if we can */
static void maybe_start_some_streams(
@ -117,7 +119,7 @@ static void maybe_start_some_streams(
static void connectivity_state_set(
grpc_chttp2_transport_global *transport_global,
grpc_connectivity_state state);
grpc_connectivity_state state, const char *reason);
/*
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
@ -235,7 +237,7 @@ static void init_transport(grpc_chttp2_transport *t,
is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
t->writing.is_client = is_client;
grpc_connectivity_state_init(&t->channel_callback.state_tracker,
GRPC_CHANNEL_READY);
GRPC_CHANNEL_READY, "transport");
gpr_slice_buffer_init(&t->global.qbuf);
@ -329,7 +331,8 @@ static void destroy_transport(grpc_transport *gt) {
static void close_transport_locked(grpc_chttp2_transport *t) {
if (!t->closed) {
t->closed = 1;
connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE);
connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE,
"close_transport");
if (t->ep) {
grpc_endpoint_shutdown(t->ep);
}
@ -536,7 +539,8 @@ void grpc_chttp2_add_incoming_goaway(
gpr_free(msg);
gpr_slice_unref(goaway_text);
transport_global->seen_goaway = 1;
connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE);
connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE,
"got_goaway");
}
static void maybe_start_some_streams(
@ -561,7 +565,8 @@ static void maybe_start_some_streams(
transport_global->next_stream_id += 2;
if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE);
connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
"no_more_stream_ids");
}
stream_global->outgoing_window =
@ -689,6 +694,7 @@ static void send_ping_locked(grpc_chttp2_transport *t,
static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
int close_transport = 0;
lock(t);
@ -708,9 +714,7 @@ static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
t->global.last_incoming_stream_id,
grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
if (!grpc_chttp2_has_streams(t)) {
close_transport_locked(t);
}
close_transport = !grpc_chttp2_has_streams(t);
}
if (op->set_accept_stream != NULL) {
@ -723,6 +727,10 @@ static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
add_to_pollset_locked(t, op->bind_pollset);
}
if (op->bind_pollset_set) {
add_to_pollset_set_locked(t, op->bind_pollset_set);
}
if (op->send_ping) {
send_ping_locked(t, op->send_ping);
}
@ -732,6 +740,12 @@ static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
}
unlock(t);
if (close_transport) {
lock(t);
close_transport_locked(t);
unlock(t);
}
}
/*
@ -1008,12 +1022,12 @@ static void schedule_closure_for_connectivity(void *a,
static void connectivity_state_set(
grpc_chttp2_transport_global *transport_global,
grpc_connectivity_state state) {
grpc_connectivity_state state, const char *reason) {
GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
grpc_connectivity_state_set_with_scheduler(
&TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
state, schedule_closure_for_connectivity, transport_global);
state, schedule_closure_for_connectivity, transport_global, reason);
}
void grpc_chttp2_schedule_closure(
@ -1041,6 +1055,13 @@ static void add_to_pollset_locked(grpc_chttp2_transport *t,
}
}
static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
grpc_pollset_set *pollset_set) {
if (t->ep) {
grpc_endpoint_add_to_pollset_set(t->ep, pollset_set);
}
}
/*
* TRACING
*/

@ -34,11 +34,33 @@
#include "src/core/transport/connectivity_state.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
int grpc_connectivity_state_trace = 0;
const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
switch (state) {
case GRPC_CHANNEL_IDLE:
return "IDLE";
case GRPC_CHANNEL_CONNECTING:
return "CONNECTING";
case GRPC_CHANNEL_READY:
return "READY";
case GRPC_CHANNEL_TRANSIENT_FAILURE:
return "TRANSIENT_FAILURE";
case GRPC_CHANNEL_FATAL_FAILURE:
return "FATAL_FAILURE";
}
abort();
return "UNKNOWN";
}
void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state init_state) {
grpc_connectivity_state init_state,
const char *name) {
tracker->current_state = init_state;
tracker->watchers = NULL;
tracker->name = gpr_strdup(name);
}
void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) {
@ -54,6 +76,7 @@ void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) {
}
gpr_free(w);
}
gpr_free(tracker->name);
}
grpc_connectivity_state grpc_connectivity_state_check(
@ -64,6 +87,11 @@ grpc_connectivity_state grpc_connectivity_state_check(
int grpc_connectivity_state_notify_on_state_change(
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current,
grpc_iomgr_closure *notify) {
if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "CONWATCH: %s: from %s [cur=%s]", tracker->name,
grpc_connectivity_state_name(*current),
grpc_connectivity_state_name(tracker->current_state));
}
if (tracker->current_state != *current) {
*current = tracker->current_state;
grpc_iomgr_add_callback(notify);
@ -79,12 +107,19 @@ int grpc_connectivity_state_notify_on_state_change(
void grpc_connectivity_state_set_with_scheduler(
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state,
void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg) {
void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg,
const char *reason) {
grpc_connectivity_state_watcher *new = NULL;
grpc_connectivity_state_watcher *w;
if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "SET: %s: %s --> %s [%s]", tracker->name,
grpc_connectivity_state_name(tracker->current_state),
grpc_connectivity_state_name(state), reason);
}
if (tracker->current_state == state) {
return;
}
GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_FATAL_FAILURE);
tracker->current_state = state;
while ((w = tracker->watchers)) {
tracker->watchers = w->next;
@ -106,7 +141,8 @@ static void default_scheduler(void *ignored, grpc_iomgr_closure *closure) {
}
void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state state) {
grpc_connectivity_state state,
const char *reason) {
grpc_connectivity_state_set_with_scheduler(tracker, state, default_scheduler,
NULL);
NULL, reason);
}

@ -51,17 +51,24 @@ typedef struct {
grpc_connectivity_state current_state;
/** all our watchers */
grpc_connectivity_state_watcher *watchers;
/** a name to help debugging */
char *name;
} grpc_connectivity_state_tracker;
extern int grpc_connectivity_state_trace;
void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state init_state);
grpc_connectivity_state init_state,
const char *name);
void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker);
void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state state);
grpc_connectivity_state state,
const char *reason);
void grpc_connectivity_state_set_with_scheduler(
grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state,
void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg);
void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg,
const char *reason);
grpc_connectivity_state grpc_connectivity_state_check(
grpc_connectivity_state_tracker *tracker);

@ -109,6 +109,8 @@ typedef struct grpc_transport_op {
void *set_accept_stream_user_data;
/** add this transport to a pollset */
grpc_pollset *bind_pollset;
/** add this transport to a pollset_set */
grpc_pollset_set *bind_pollset_set;
/** send a ping, call this back if not NULL */
grpc_iomgr_closure *send_ping;
} grpc_transport_op;

@ -51,7 +51,7 @@ std::shared_ptr<ChannelInterface> CreateChannel(
cp_args.SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING,
user_agent_prefix.str());
return creds ? creds->CreateChannel(target, cp_args)
: std::shared_ptr<ChannelInterface>(
new Channel(target, grpc_lame_client_channel_create(NULL)));
: std::shared_ptr<ChannelInterface>(new Channel(
target, grpc_lame_client_channel_create(NULL)));
}
} // namespace grpc

@ -40,6 +40,7 @@
#include <grpc++/impl/sync.h>
#include <grpc++/time.h>
#include "src/core/census/grpc_context.h"
#include "src/core/channel/compress_filter.h"
#include "src/cpp/common/create_auth_context.h"
@ -190,4 +191,8 @@ grpc::string ServerContext::peer() const {
return peer;
}
const struct census_context* ServerContext::census_context() const {
return grpc_census_call_get_context(call_);
}
} // namespace grpc

@ -169,7 +169,7 @@ grpcsharp_metadata_array_add(grpc_metadata_array *array, const char *key,
GPR_EXPORT gpr_intptr GPR_CALLTYPE
grpcsharp_metadata_array_count(grpc_metadata_array *array) {
return (gpr_intptr) array->count;
return (gpr_intptr)array->count;
}
GPR_EXPORT const char *GPR_CALLTYPE
@ -184,10 +184,10 @@ grpcsharp_metadata_array_get_value(grpc_metadata_array *array, size_t index) {
return array->metadata[index].value;
}
GPR_EXPORT gpr_intptr GPR_CALLTYPE
grpcsharp_metadata_array_get_value_length(grpc_metadata_array *array, size_t index) {
GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_metadata_array_get_value_length(
grpc_metadata_array *array, size_t index) {
GPR_ASSERT(index < array->count);
return (gpr_intptr) array->metadata[index].value_length;
return (gpr_intptr)array->metadata[index].value_length;
}
/* Move contents of metadata array */
@ -306,8 +306,7 @@ grpcsharp_batch_context_server_rpc_new_method(
return ctx->server_rpc_new.call_details.method;
}
GPR_EXPORT const char *GPR_CALLTYPE
grpcsharp_batch_context_server_rpc_new_host(
GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_host(
const grpcsharp_batch_context *ctx) {
return ctx->server_rpc_new.call_details.host;
}
@ -657,20 +656,17 @@ grpcsharp_call_send_close_from_client(grpc_call *call,
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_send_status_from_server(grpc_call *call,
grpcsharp_batch_context *ctx,
grpc_status_code status_code,
const char *status_details,
grpc_metadata_array *trailing_metadata) {
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code,
const char *status_details, grpc_metadata_array *trailing_metadata) {
/* TODO: don't use magic number */
grpc_op ops[1];
ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
ops[0].data.send_status_from_server.status = status_code;
ops[0].data.send_status_from_server.status_details =
gpr_strdup(status_details);
grpcsharp_metadata_array_move(&(ctx->send_status_from_server.trailing_metadata),
trailing_metadata);
grpcsharp_metadata_array_move(
&(ctx->send_status_from_server.trailing_metadata), trailing_metadata);
ops[0].data.send_status_from_server.trailing_metadata_count =
ctx->send_status_from_server.trailing_metadata.count;
ops[0].data.send_status_from_server.trailing_metadata =

@ -41,7 +41,8 @@ var interop_server = require('../interop/interop_server.js');
function runTest(iterations, callback) {
var testServer = interop_server.getServer(0, false);
testServer.server.listen();
var client = new testProto.TestService('localhost:' + testServer.port);
var client = new testProto.TestService('localhost:' + testServer.port,
grpc.Credentials.createInsecure());
function runIterations(finish) {
var start = process.hrtime();

@ -61,7 +61,8 @@ var interop_server = require('../interop/interop_server.js');
function runTest(concurrent_calls, seconds, callback) {
var testServer = interop_server.getServer(0, false);
testServer.server.listen();
var client = new testProto.TestService('localhost:' + testServer.port);
var client = new testProto.TestService('localhost:' + testServer.port,
grpc.Credentials.createInsecure());
var warmup_num = 100;

@ -40,7 +40,8 @@ var path = require('path');
var _ = require('lodash');
var grpc = require('..');
var examples = grpc.load(__dirname + '/route_guide.proto').examples;
var client = new examples.RouteGuide('localhost:50051');
var client = new examples.RouteGuide('localhost:50051',
grpc.Credentials.createInsecure());
var COORD_FACTOR = 1e7;

@ -38,7 +38,8 @@ var examples = grpc.load(__dirname + '/stock.proto').examples;
* This exports a client constructor for the Stock service. The usage looks like
*
* var StockClient = require('stock_client.js');
* var stockClient = new StockClient(server_address);
* var stockClient = new StockClient(server_address,
* grpc.Credentials.createInsecure());
* stockClient.getLastTradePrice({symbol: 'GOOG'}, function(error, response) {
* console.log(error || response);
* });

@ -98,31 +98,30 @@ NAN_METHOD(Channel::New) {
if (args.IsConstructCall()) {
if (!args[0]->IsString()) {
return NanThrowTypeError("Channel expects a string and an object");
return NanThrowTypeError(
"Channel expects a string, a credential and an object");
}
grpc_channel *wrapped_channel;
// Owned by the Channel object
NanUtf8String *host = new NanUtf8String(args[0]);
NanUtf8String *host_override = NULL;
if (args[1]->IsUndefined()) {
grpc_credentials *creds;
if (!Credentials::HasInstance(args[1])) {
return NanThrowTypeError(
"Channel's second argument must be a credential");
}
Credentials *creds_object = ObjectWrap::Unwrap<Credentials>(
args[1]->ToObject());
creds = creds_object->GetWrappedCredentials();
grpc_channel_args *channel_args_ptr;
if (args[2]->IsUndefined()) {
channel_args_ptr = NULL;
wrapped_channel = grpc_insecure_channel_create(**host, NULL);
} else if (args[1]->IsObject()) {
grpc_credentials *creds = NULL;
Handle<Object> args_hash(args[1]->ToObject()->Clone());
} else if (args[2]->IsObject()) {
Handle<Object> args_hash(args[2]->ToObject()->Clone());
if (args_hash->HasOwnProperty(NanNew(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG))) {
host_override = new NanUtf8String(args_hash->Get(NanNew(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)));
}
if (args_hash->HasOwnProperty(NanNew("credentials"))) {
Handle<Value> creds_value = args_hash->Get(NanNew("credentials"));
if (!Credentials::HasInstance(creds_value)) {
return NanThrowTypeError(
"credentials arg must be a Credentials object");
}
Credentials *creds_object =
ObjectWrap::Unwrap<Credentials>(creds_value->ToObject());
creds = creds_object->GetWrappedCredentials();
args_hash->Delete(NanNew("credentials"));
}
Handle<Array> keys(args_hash->GetOwnPropertyNames());
grpc_channel_args channel_args;
channel_args.num_args = keys->Length();
@ -149,16 +148,19 @@ NAN_METHOD(Channel::New) {
return NanThrowTypeError("Arg values must be strings");
}
}
if (creds == NULL) {
wrapped_channel = grpc_insecure_channel_create(**host, &channel_args);
} else {
wrapped_channel =
grpc_secure_channel_create(creds, **host, &channel_args);
}
free(channel_args.args);
channel_args_ptr = &channel_args;
} else {
return NanThrowTypeError("Channel expects a string and an object");
}
if (creds == NULL) {
wrapped_channel = grpc_insecure_channel_create(**host, channel_args_ptr);
} else {
wrapped_channel =
grpc_secure_channel_create(creds, **host, channel_args_ptr);
}
if (channel_args_ptr != NULL) {
free(channel_args_ptr->args);
}
Channel *channel;
if (host_override == NULL) {
channel = new Channel(wrapped_channel, host);
@ -168,8 +170,8 @@ NAN_METHOD(Channel::New) {
channel->Wrap(args.This());
NanReturnValue(args.This());
} else {
const int argc = 2;
Local<Value> argv[argc] = {args[0], args[1]};
const int argc = 3;
Local<Value> argv[argc] = {args[0], args[1], args[2]};
NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv));
}
}

@ -81,6 +81,8 @@ void Credentials::Init(Handle<Object> exports) {
NanNew<FunctionTemplate>(CreateGce)->GetFunction());
ctr->Set(NanNew("createIam"),
NanNew<FunctionTemplate>(CreateIam)->GetFunction());
ctr->Set(NanNew("createInsecure"),
NanNew<FunctionTemplate>(CreateInsecure)->GetFunction());
constructor = new NanCallback(ctr);
exports->Set(NanNew("Credentials"), ctr);
}
@ -92,9 +94,6 @@ bool Credentials::HasInstance(Handle<Value> val) {
Handle<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
NanEscapableScope();
if (credentials == NULL) {
return NanEscapeScope(NanNull());
}
const int argc = 1;
Handle<Value> argv[argc] = {
NanNew<External>(reinterpret_cast<void *>(credentials))};
@ -128,7 +127,11 @@ NAN_METHOD(Credentials::New) {
NAN_METHOD(Credentials::CreateDefault) {
NanScope();
NanReturnValue(WrapStruct(grpc_google_default_credentials_create()));
grpc_credentials *creds = grpc_google_default_credentials_create();
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateSsl) {
@ -152,9 +155,12 @@ NAN_METHOD(Credentials::CreateSsl) {
return NanThrowTypeError(
"createSSl's third argument must be a Buffer if provided");
}
NanReturnValue(WrapStruct(grpc_ssl_credentials_create(
root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair)));
grpc_credentials *creds = grpc_ssl_credentials_create(
root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair);
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateComposite) {
@ -169,13 +175,21 @@ NAN_METHOD(Credentials::CreateComposite) {
}
Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
NanReturnValue(WrapStruct(grpc_composite_credentials_create(
creds1->wrapped_credentials, creds2->wrapped_credentials)));
grpc_credentials *creds = grpc_composite_credentials_create(
creds1->wrapped_credentials, creds2->wrapped_credentials);
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateGce) {
NanScope();
NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create()));
grpc_credentials *creds = grpc_compute_engine_credentials_create();
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateIam) {
@ -188,8 +202,17 @@ NAN_METHOD(Credentials::CreateIam) {
}
NanUtf8String auth_token(args[0]);
NanUtf8String auth_selector(args[1]);
NanReturnValue(
WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector)));
grpc_credentials *creds = grpc_iam_credentials_create(*auth_token,
*auth_selector);
if (creds == NULL) {
NanReturnNull();
}
NanReturnValue(WrapStruct(creds));
}
NAN_METHOD(Credentials::CreateInsecure) {
NanScope();
NanReturnValue(WrapStruct(NULL));
}
} // namespace node

@ -68,6 +68,7 @@ class Credentials : public ::node::ObjectWrap {
static NAN_METHOD(CreateGce);
static NAN_METHOD(CreateFake);
static NAN_METHOD(CreateIam);
static NAN_METHOD(CreateInsecure);
static NanCallback *constructor;
// Used for typechecking instances of this javascript class
static v8::Persistent<v8::FunctionTemplate> fun_tpl;

@ -48,7 +48,7 @@ var grpc = require('bindings')('grpc');
* @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
* @return {Object<string, *>} The resulting gRPC object
*/
function loadObject(value) {
exports.loadObject = function loadObject(value) {
var result = {};
if (value.className === 'Namespace') {
_.each(value.children, function(child) {
@ -62,7 +62,9 @@ function loadObject(value) {
} else {
return value;
}
}
};
var loadObject = exports.loadObject;
/**
* Load a gRPC object from a .proto file.
@ -71,7 +73,7 @@ function loadObject(value) {
* 'json'. Defaults to 'proto'
* @return {Object<string, *>} The resulting gRPC object
*/
function load(filename, format) {
exports.load = function load(filename, format) {
if (!format) {
format = 'proto';
}
@ -88,7 +90,7 @@ function load(filename, format) {
}
return loadObject(builder.ns);
}
};
/**
* Get a function that a client can use to update metadata with authentication
@ -97,7 +99,7 @@ function load(filename, format) {
* @param {Object} credential The credential object to use
* @return {function(Object, callback)} Metadata updater function
*/
function getGoogleAuthDelegate(credential) {
exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) {
/**
* Update a metadata object with authentication information.
* @param {string} authURI The uri to authenticate to
@ -120,20 +122,10 @@ function getGoogleAuthDelegate(credential) {
callback(null, metadata);
});
};
}
/**
* See docs for loadObject
*/
exports.loadObject = loadObject;
};
/**
* See docs for load
*/
exports.load = load;
/**
* See docs for Server
* @see module:src/server.Server
*/
exports.Server = server.Server;
@ -141,6 +133,7 @@ exports.Server = server.Server;
* Status name to code number mapping
*/
exports.status = grpc.status;
/**
* Call error name to code number mapping
*/
@ -156,6 +149,7 @@ exports.Credentials = grpc.Credentials;
*/
exports.ServerCredentials = grpc.ServerCredentials;
exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
/**
* @see module:src/client.makeClientConstructor
*/
exports.makeGenericClientConstructor = client.makeClientConstructor;

@ -397,6 +397,7 @@ var test_cases = {
function runTest(address, host_override, test_case, tls, test_ca, done) {
// TODO(mlumish): enable TLS functionality
var options = {};
var creds;
if (tls) {
var ca_path;
if (test_ca) {
@ -405,13 +406,14 @@ function runTest(address, host_override, test_case, tls, test_ca, done) {
ca_path = process.env.SSL_CERT_FILE;
}
var ca_data = fs.readFileSync(ca_path);
var creds = grpc.Credentials.createSsl(ca_data);
options.credentials = creds;
creds = grpc.Credentials.createSsl(ca_data);
if (host_override) {
options['grpc.ssl_target_name_override'] = host_override;
}
} else {
creds = grpc.Credentials.createInsecure();
}
var client = new testProto.TestService(address, options);
var client = new testProto.TestService(address, creds, options);
test_cases[test_case](client, done);
}

@ -0,0 +1,22 @@
{
"tags": {
"allowUnknownTags": true
},
"source": {
"include": [ "index.js", "src" ],
"includePattern": ".+\\.js(doc)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"opts": {
"package": "package.json",
"readme": "README.md"
},
"plugins": [],
"templates": {
"cleverLinks": false,
"monospaceLinks": false,
"default": {
"outputSourceFiles": true
}
}
}

@ -21,7 +21,8 @@
},
"scripts": {
"lint": "node ./node_modules/jshint/bin/jshint src test examples interop index.js",
"test": "node ./node_modules/mocha/bin/mocha && npm run-script lint"
"test": "node ./node_modules/mocha/bin/mocha && npm run-script lint",
"gen_docs": "./node_modules/.bin/jsdoc -c jsdoc_conf.json"
},
"dependencies": {
"bindings": "^1.2.0",
@ -32,6 +33,7 @@
"devDependencies": {
"async": "^0.9.0",
"google-auth-library": "^0.9.2",
"jsdoc": "^3.3.2",
"jshint": "^2.5.0",
"minimist": "^1.1.0",
"mocha": "~1.21.0",

@ -31,6 +31,11 @@
*
*/
/**
* Server module
* @module
*/
'use strict';
var _ = require('lodash');
@ -72,6 +77,7 @@ function ClientWritableStream(call, serialize) {
/**
* Attempt to write the given chunk. Calls the callback when done. This is an
* implementation of a method needed for implementing stream.Writable.
* @access private
* @param {Buffer} chunk The chunk to write
* @param {string} encoding Ignored
* @param {function(Error=)} callback Called when the write is complete
@ -110,6 +116,7 @@ function ClientReadableStream(call, deserialize) {
/**
* Read the next object from the stream.
* @access private
* @param {*} size Ignored because we use objectMode=true
*/
function _read(size) {
@ -519,16 +526,18 @@ var requester_makers = {
* @param {string} serviceName The name of the service
* @return {function(string, Object)} New client constructor
*/
function makeClientConstructor(methods, serviceName) {
exports.makeClientConstructor = function(methods, serviceName) {
/**
* Create a client with the given methods
* @constructor
* @param {string} address The address of the server to connect to
* @param {grpc.Credentials} credentials Credentials to use to connect
* to the server
* @param {Object} options Options to pass to the underlying channel
* @param {function(string, Object, function)=} updateMetadata function to
* update the metadata for each request
*/
function Client(address, options, updateMetadata) {
function Client(address, credentials, options, updateMetadata) {
if (!updateMetadata) {
updateMetadata = function(uri, metadata, callback) {
callback(null, metadata);
@ -538,7 +547,7 @@ function makeClientConstructor(methods, serviceName) {
options = {};
}
options['grpc.primary_user_agent'] = 'grpc-node/' + version;
this.channel = new grpc.Channel(address, options);
this.channel = new grpc.Channel(address, credentials, options);
this.server_address = address.replace(/\/$/, '');
this.auth_uri = this.server_address + '/' + serviceName;
this.updateMetadata = updateMetadata;
@ -568,7 +577,7 @@ function makeClientConstructor(methods, serviceName) {
});
return Client;
}
};
/**
* Creates a constructor for clients for the given service
@ -576,22 +585,18 @@ function makeClientConstructor(methods, serviceName) {
* for
* @return {function(string, Object)} New client constructor
*/
function makeProtobufClientConstructor(service) {
exports.makeProtobufClientConstructor = function(service) {
var method_attrs = common.getProtobufServiceAttrs(service, service.name);
var Client = makeClientConstructor(method_attrs);
var Client = exports.makeClientConstructor(method_attrs);
Client.service = service;
return Client;
}
exports.makeClientConstructor = makeClientConstructor;
exports.makeProtobufClientConstructor = makeProtobufClientConstructor;
};
/**
* See docs for client.status
* Map of status code names to status codes
*/
exports.status = grpc.status;
/**
* See docs for client.callError
*/

@ -31,6 +31,10 @@
*
*/
/**
* @module
*/
'use strict';
var _ = require('lodash');
@ -40,7 +44,7 @@ var _ = require('lodash');
* @param {function()} cls The constructor of the message type to deserialize
* @return {function(Buffer):cls} The deserialization function
*/
function deserializeCls(cls) {
exports.deserializeCls = function deserializeCls(cls) {
/**
* Deserialize a buffer to a message object
* @param {Buffer} arg_buf The buffer to deserialize
@ -51,14 +55,16 @@ function deserializeCls(cls) {
// and longs as strings (second argument)
return cls.decode(arg_buf).toRaw(false, true);
};
}
};
var deserializeCls = exports.deserializeCls;
/**
* Get a function that serializes objects to a buffer by protobuf class.
* @param {function()} Cls The constructor of the message type to serialize
* @return {function(Cls):Buffer} The serialization function
*/
function serializeCls(Cls) {
exports.serializeCls = function serializeCls(Cls) {
/**
* Serialize an object to a Buffer
* @param {Object} arg The object to serialize
@ -67,14 +73,16 @@ function serializeCls(Cls) {
return function serialize(arg) {
return new Buffer(new Cls(arg).encode().toBuffer());
};
}
};
var serializeCls = exports.serializeCls;
/**
* Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
* @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
* @return {string} The fully qualified name of the value
*/
function fullyQualifiedName(value) {
exports.fullyQualifiedName = function fullyQualifiedName(value) {
if (value === null || value === undefined) {
return '';
}
@ -89,7 +97,9 @@ function fullyQualifiedName(value) {
}
}
return name;
}
};
var fullyQualifiedName = exports.fullyQualifiedName;
/**
* Wrap a function to pass null-like values through without calling it. If no
@ -97,7 +107,7 @@ function fullyQualifiedName(value) {
* @param {?function} func The function to wrap
* @return {function} The wrapped function
*/
function wrapIgnoreNull(func) {
exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
if (!func) {
return _.identity;
}
@ -107,14 +117,14 @@ function wrapIgnoreNull(func) {
}
return func(arg);
};
}
};
/**
* Return a map from method names to method attributes for the service.
* @param {ProtoBuf.Reflect.Service} service The service to get attributes for
* @return {Object} The attributes map
*/
function getProtobufServiceAttrs(service) {
exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service) {
var prefix = '/' + fullyQualifiedName(service) + '/';
return _.object(_.map(service.children, function(method) {
return [_.camelCase(method.name), {
@ -127,26 +137,4 @@ function getProtobufServiceAttrs(service) {
responseDeserialize: deserializeCls(method.resolvedResponseType.build())
}];
}));
}
/**
* See docs for deserializeCls
*/
exports.deserializeCls = deserializeCls;
/**
* See docs for serializeCls
*/
exports.serializeCls = serializeCls;
/**
* See docs for fullyQualifiedName
*/
exports.fullyQualifiedName = fullyQualifiedName;
/**
* See docs for wrapIgnoreNull
*/
exports.wrapIgnoreNull = wrapIgnoreNull;
exports.getProtobufServiceAttrs = getProtobufServiceAttrs;
};

@ -31,6 +31,11 @@
*
*/
/**
* Server module
* @module
*/
'use strict';
var _ = require('lodash');
@ -50,6 +55,7 @@ var EventEmitter = require('events').EventEmitter;
/**
* Handle an error on a call by sending it as a status
* @access private
* @param {grpc.Call} call The call to send the error on
* @param {Object} error The error object
*/
@ -82,6 +88,7 @@ function handleError(call, error) {
/**
* Wait for the client to close, then emit a cancelled event if the client
* cancelled.
* @access private
* @param {grpc.Call} call The call object to wait on
* @param {EventEmitter} emitter The event emitter to emit the cancelled event
* on
@ -102,6 +109,7 @@ function waitForCancel(call, emitter) {
/**
* Send a response to a unary or client streaming call.
* @access private
* @param {grpc.Call} call The call to respond on
* @param {*} value The value to respond with
* @param {function(*):Buffer=} serialize Serialization function for the
@ -130,6 +138,7 @@ function sendUnaryResponse(call, value, serialize, metadata) {
/**
* Initialize a writable stream. This is used for both the writable and duplex
* stream constructors.
* @access private
* @param {Writable} stream The stream to set up
* @param {function(*):Buffer=} Serialization function for responses
*/
@ -203,6 +212,7 @@ function setUpWritable(stream, serialize) {
/**
* Initialize a readable stream. This is used for both the readable and duplex
* stream constructors.
* @access private
* @param {Readable} stream The stream to initialize
* @param {function(Buffer):*=} deserialize Deserialization function for
* incoming data.
@ -242,6 +252,7 @@ function ServerWritableStream(call, serialize) {
/**
* Start writing a chunk of data. This is an implementation of a method required
* for implementing stream.Writable.
* @access private
* @param {Buffer} chunk The chunk of data to write
* @param {string} encoding Ignored
* @param {function(Error=)} callback Callback to indicate that the write is
@ -266,6 +277,11 @@ function _write(chunk, encoding, callback) {
ServerWritableStream.prototype._write = _write;
/**
* Send the initial metadata for a writable stream.
* @param {Object<String, Array<(String|Buffer)>>} responseMetadata Metadata
* to send
*/
function sendMetadata(responseMetadata) {
/* jshint validthis: true */
if (!this.call.metadataSent) {
@ -281,6 +297,10 @@ function sendMetadata(responseMetadata) {
}
}
/**
* @inheritdoc
* @alias module:src/server~ServerWritableStream#sendMetadata
*/
ServerWritableStream.prototype.sendMetadata = sendMetadata;
util.inherits(ServerReadableStream, Readable);
@ -301,6 +321,7 @@ function ServerReadableStream(call, deserialize) {
/**
* Start reading from the gRPC data source. This is an implementation of a
* method required for implementing stream.Readable
* @access private
* @param {number} size Ignored
*/
function _read(size) {
@ -388,6 +409,7 @@ ServerDuplexStream.prototype.getPeer = getPeer;
/**
* Fully handle a unary call
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
* @param {Object} metadata Metadata from the client
@ -442,6 +464,7 @@ function handleUnary(call, handler, metadata) {
/**
* Fully handle a server streaming call
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
* @param {Object} metadata Metadata from the client
@ -470,6 +493,7 @@ function handleServerStreaming(call, handler, metadata) {
/**
* Fully handle a client streaming call
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
* @param {Object} metadata Metadata from the client
@ -504,6 +528,7 @@ function handleClientStreaming(call, handler, metadata) {
/**
* Fully handle a bidirectional streaming call
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
* @param {Object} metadata Metadata from the client
@ -587,7 +612,8 @@ function Server(options) {
}
server.requestCall(handleNewCall);
};
/** Shuts down the server.
/**
* Shuts down the server.
*/
this.shutdown = function() {
server.shutdown();
@ -621,6 +647,15 @@ Server.prototype.register = function(name, handler, serialize, deserialize,
return true;
};
/**
* Add a service to the server, with a corresponding implementation. If you are
* generating this from a proto file, you should instead use
* addProtoService.
* @param {Object<String, *>} service The service descriptor, as
* {@link module:src/common.getProtobufServiceAttrs} returns
* @param {Object<String, function>} implementation Map of method names to
* method implementation for the provided service.
*/
Server.prototype.addService = function(service, implementation) {
if (this.started) {
throw new Error('Can\'t add a service to a started server.');
@ -658,6 +693,12 @@ Server.prototype.addService = function(service, implementation) {
});
};
/**
* Add a proto service to the server, with a corresponding implementation
* @param {Protobuf.Reflect.Service} service The proto service descriptor
* @param {Object<String, function>} implementation Map of method names to
* method implementation for the provided service.
*/
Server.prototype.addProtoService = function(service, implementation) {
this.addService(common.getProtobufServiceAttrs(service), implementation);
};
@ -681,6 +722,6 @@ Server.prototype.bind = function(port, creds) {
};
/**
* See documentation for Server
* @see module:src/server~Server
*/
exports.Server = Server;

@ -48,6 +48,8 @@ function getDeadline(timeout_secs) {
return deadline;
}
var insecureCreds = grpc.Credentials.createInsecure();
describe('call', function() {
var channel;
var server;
@ -55,7 +57,7 @@ describe('call', function() {
server = new grpc.Server();
var port = server.addHttp2Port('localhost:0');
server.start();
channel = new grpc.Channel('localhost:' + port);
channel = new grpc.Channel('localhost:' + port, insecureCreds);
});
after(function() {
server.shutdown();
@ -82,7 +84,7 @@ describe('call', function() {
});
});
it('should fail with a closed channel', function() {
var local_channel = new grpc.Channel('hostname');
var local_channel = new grpc.Channel('hostname', insecureCreds);
local_channel.close();
assert.throws(function() {
new grpc.Call(channel, 'method');

@ -36,11 +36,13 @@
var assert = require('assert');
var grpc = require('bindings')('grpc.node');
var insecureCreds = grpc.Credentials.createInsecure();
describe('channel', function() {
describe('constructor', function() {
it('should require a string for the first argument', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname');
new grpc.Channel('hostname', insecureCreds);
});
assert.throws(function() {
new grpc.Channel();
@ -49,38 +51,49 @@ describe('channel', function() {
new grpc.Channel(5);
});
});
it('should accept an object for the second parameter', function() {
it('should require a credential for the second argument', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname', {});
new grpc.Channel('hostname', insecureCreds);
});
assert.throws(function() {
new grpc.Channel('hostname', 5);
});
assert.throws(function() {
new grpc.Channel('hostname');
});
});
it('should accept an object for the third argument', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname', insecureCreds, {});
});
assert.throws(function() {
new grpc.Channel('hostname', insecureCreds, 'abc');
});
});
it('should only accept objects with string or int values', function() {
assert.doesNotThrow(function() {
new grpc.Channel('hostname', {'key' : 'value'});
new grpc.Channel('hostname', insecureCreds,{'key' : 'value'});
});
assert.doesNotThrow(function() {
new grpc.Channel('hostname', {'key' : 5});
new grpc.Channel('hostname', insecureCreds, {'key' : 5});
});
assert.throws(function() {
new grpc.Channel('hostname', {'key' : null});
new grpc.Channel('hostname', insecureCreds, {'key' : null});
});
assert.throws(function() {
new grpc.Channel('hostname', {'key' : new Date()});
new grpc.Channel('hostname', insecureCreds, {'key' : new Date()});
});
});
});
describe('close', function() {
it('should succeed silently', function() {
var channel = new grpc.Channel('hostname', {});
var channel = new grpc.Channel('hostname', insecureCreds, {});
assert.doesNotThrow(function() {
channel.close();
});
});
it('should be idempotent', function() {
var channel = new grpc.Channel('hostname', {});
var channel = new grpc.Channel('hostname', insecureCreds, {});
assert.doesNotThrow(function() {
channel.close();
channel.close();
@ -89,7 +102,7 @@ describe('channel', function() {
});
describe('getTarget', function() {
it('should return a string', function() {
var channel = new grpc.Channel('localhost', {});
var channel = new grpc.Channel('localhost', insecureCreds, {});
assert.strictEqual(typeof channel.getTarget(), 'string');
});
});

@ -57,6 +57,8 @@ function multiDone(done, count) {
};
}
var insecureCreds = grpc.Credentials.createInsecure();
describe('end-to-end', function() {
var server;
var channel;
@ -64,7 +66,7 @@ describe('end-to-end', function() {
server = new grpc.Server();
var port_num = server.addHttp2Port('0.0.0.0:0');
server.start();
channel = new grpc.Channel('localhost:' + port_num);
channel = new grpc.Channel('localhost:' + port_num, insecureCreds);
});
after(function() {
server.shutdown();

@ -56,7 +56,8 @@ describe('Health Checking', function() {
before(function() {
var port_num = healthServer.bind('0.0.0.0:0');
healthServer.start();
healthClient = new health.Client('localhost:' + port_num);
healthClient = new health.Client('localhost:' + port_num,
grpc.Credentials.createInsecure());
});
after(function() {
healthServer.shutdown();

@ -53,7 +53,8 @@ describe('Math client', function() {
before(function(done) {
var port_num = server.bind('0.0.0.0:0');
server.start();
math_client = new math.Math('localhost:' + port_num);
math_client = new math.Math('localhost:' + port_num,
grpc.Credentials.createInsecure());
done();
});
after(function() {

@ -124,7 +124,7 @@ describe('Echo service', function() {
});
var port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(echo_service);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {
@ -169,7 +169,8 @@ describe('Generic client and server', function() {
var port = server.bind('localhost:0');
server.start();
var Client = grpc.makeGenericClientConstructor(string_service_attrs);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port,
grpc.Credentials.createInsecure());
});
after(function() {
server.shutdown();
@ -216,7 +217,7 @@ describe('Echo metadata', function() {
});
var port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {
@ -260,9 +261,8 @@ describe('Echo metadata', function() {
});
it('shows the correct user-agent string', function(done) {
var version = require('../package.json').version;
var call = client.unary({}, function(err, data) {
assert.ifError(err);
}, {key: ['value']});
var call = client.unary({}, function(err, data) { assert.ifError(err); },
{key: ['value']});
call.on('metadata', function(metadata) {
assert(_.startsWith(metadata['user-agent'], 'grpc-node/' + version));
done();
@ -338,7 +338,7 @@ describe('Other conditions', function() {
});
port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {
@ -383,7 +383,8 @@ describe('Other conditions', function() {
};
var Client = surface_client.makeClientConstructor(test_service_attrs,
'TestService');
misbehavingClient = new Client('localhost:' + port);
misbehavingClient = new Client('localhost:' + port,
grpc.Credentials.createInsecure());
});
it('should respond correctly to a unary call', function(done) {
misbehavingClient.unary(badArg, function(err, data) {
@ -603,7 +604,7 @@ describe('Cancelling surface client', function() {
});
var port = server.bind('localhost:0');
var Client = surface_client.makeProtobufClientConstructor(mathService);
client = new Client('localhost:' + port);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
});
after(function() {

@ -33,16 +33,18 @@
<%def name="to_windows_path(path)">${path.replace('/','\\')}</%def>\
<%
build_from_project_file = set(['gpr',
'grpc',
'grpc_unsecure',
'gpr_test_util',
'grpc',
'grpc_test_util',
'grpc_test_util_unsecure',
'grpc_unsecure',
'grpc++',
'grpc++_unsecure'
])
buildable_targets = [ target for target in targets + libs
if target.build in ['all', 'test', 'private', 'tool', 'benchmark'] and
target.language in ['c', 'c++'] and
all([src.endswith('.c') for src in target.src]) and
all([(src.endswith('.c') or src.endswith('.cc') or src.endswith('.proto')) for src in target.src]) and
'windows' in target.get('platforms', ['windows']) ]
c_test_targets = [ target for target in buildable_targets if target.build == 'test' and not target.language == 'c++' ]
cxx_test_targets = [ target for target in buildable_targets if target.build == 'test' and target.language == 'c++' ]
@ -60,8 +62,19 @@ REPO_ROOT=..
OPENSSL_INCLUDES = .\packages\${get_openssl()}\build\native\include
ZLIB_INCLUDES = .\packages\${get_zlib()}\build\native\include
INCLUDES=/I$(REPO_ROOT) /I$(REPO_ROOT)\include /I$(OPENSSL_INCLUDES) /I$(ZLIB_INCLUDES)
DEFINES=/D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /D _CRT_SECURE_NO_WARNINGS
GFLAGS_INCLUDES = .\..\third_party\gflags\include
GTEST_INCLUDES = .\..\third_party\gtest\include
PROTOBUF_INCLUDES = .\..\third_party\protobuf\src
CXX_INCLUDES=/I$(GFLAGS_INCLUDES) /I$(GTEST_INCLUDES) /I$(PROTOBUF_INCLUDES)
#_SCL_SECURE_NO_WARNINGS supresses a ton of "potentially unsafe use of std lib" warnings
DEFINES=/D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /D _CRT_SECURE_NO_WARNINGS /D _SCL_SECURE_NO_WARNINGS
#important options: /TC vs. /TP: compile as C vs. compile as C++
CFLAGS=/c $(INCLUDES) /Z7 /W3 /WX- /sdl $(DEFINES) /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze-
CXXFLAGS=/c $(INCLUDES) $(CXX_INCLUDES) /Z7 /W3 /WX- /sdl $(DEFINES) /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TP /analyze-
LFLAGS=/DEBUG /INCREMENTAL /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86
OPENSSL_LIBS=.\packages\${get_openssl()}\build\native\lib\v120\Win32\Debug\static\ssleay32.lib .\packages\${get_openssl()}\build\native\lib\v120\Win32\Debug\static\libeay32.lib
@ -70,6 +83,12 @@ GENERAL_LIBS=advapi32.lib comdlg32.lib gdi32.lib kernel32.lib odbc32.lib odbccp3
ZLIB_LIBS=.\packages\${get_zlib()}\build\native\lib\v120\Win32\Debug\static\cdecl\zlib.lib
LIBS=$(OPENSSL_LIBS) $(ZLIB_LIBS) $(GENERAL_LIBS) $(WINSOCK_LIBS)
#shlwapi.lib provides PathMatchSpec() for gflags in windows
GFLAGS_LIBS=.\..\third_party\gflags\lib\Debug\gflags.lib shlwapi.lib
GTEST_LIBS=.\..\third_party\gtest\msvc\gtest\Debug\gtestd.lib
PROTOBUF_LIBS=.\..\third_party\protobuf\vsprojects\Debug\libprotobuf.lib
CXX_LIBS=$(GFLAGS_LIBS) $(GTEST_LIBS) $(PROTOBUF_LIBS)
all: buildtests
tools:
@ -99,16 +118,33 @@ buildtests_c: \
${target.name}.exe \
% endfor
echo All tests built.
echo All C tests built.
buildtests_cxx: \
% for target in cxx_test_targets:
${target.name}.exe \
% endfor
echo All tests built.
echo All C++ tests built.
% for target in buildable_targets:
## replace all .proto includes with .pb.cc / .grpc.pb.cc
%if target.src:
%for source in target.src:
%if source.endswith(".proto"):
<%
src_name_parts = source.split(".")
target.src.append(src_name_parts[0] + ".pb.cc")
target.src.append(src_name_parts[0] + ".grpc.pb.cc")
%>\
%endif
%endfor
%endif
## remove all .proto includes
<%
target.src = [item for item in target.src if not re.search('([^/]+)\.proto$', item)]
%>\
%if target.name in build_from_project_file:
build_${target.name}:
msbuild grpc.sln /t:${target.name} /p:Configuration=Debug /p:Linkage-grpc_dependencies_zlib=static
@ -116,11 +152,22 @@ build_${target.name}:
%if target.build == 'private':
Debug\${target.name}.lib: \
%else:
${target.name}.exe: build_libs \
${target.name}.exe: \
%for dep in target.get('deps', []):
%if dep in build_from_project_file:
build_${dep} \
%else:
Debug\${dep}.lib \
%endif
%endfor
%endif
$(OUT_DIR)
echo Building ${target.name}
%if target.language == 'c++':
$(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ \
%else:
$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ \
%endif
%for source in target.src:
$(REPO_ROOT)\${to_windows_path(source)} \
%endfor
@ -135,13 +182,19 @@ $(REPO_ROOT)\${to_windows_path('vsprojects/dummy.c')} \
%for dep in target.get('deps', []):
Debug\${dep}.lib \
%endfor
%if target.language == 'c++':
$(CXX_LIBS) \
%endif
$(LIBS) \
%endif
%for source in target.src:
$(OUT_DIR)\${re.search('([^/]+)\.c$', source).group(1)}.obj \
%endfor
%if not target.src:
$(OUT_DIR)\dummy.obj \
%else:
%for source in target.src:
%if re.search('([^/]+)\.c{1,2}$', source):
$(OUT_DIR)\${re.search('([^/]+)\.c{1,2}$', source).group(1)}.obj \
%endif
%endfor
%endif
%if target.build != 'private':

@ -0,0 +1,42 @@
#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
GRPC_CPP_PLUGIN_PATH=`which grpc_cpp_plugin`
cd `dirname $0`/../..
find ./test -type f -name "*.proto" |
while read p ; do
echo "processing $p"
DIR=$(dirname "$p")
protoc $p --grpc_out=./ --plugin=protoc-gen-grpc=$GRPC_CPP_PLUGIN_PATH
protoc $p --cpp_out=./
done

@ -37,26 +37,40 @@
cd `dirname $0`/../..
./tools/buildgen/generate_projects.sh
git add . #because we're using "git diff" to find changes to grpc.sln and then make files based on those changes, this prevents this file or other files from possibly being found in the diff
git diff |
grep \\+Project |
cut -d\" -f 4 |
sort -u |
grep _test$ |
while read p ; do
mkdir -p templates/vsprojects/$p
echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$p'", targets)}' > templates/vsprojects/$p/$p.vcxproj.template
done
./tools/buildgen/generate_projects-old.sh
line_number=0
git diff |
grep \\+Project |
cut -d\" -f 4 |
sort -u |
grep -v _test$ |
grep -A2 \\+Project | #find "Project" immediately after a backslash (escaped), plus 2 additional lines to capture the "libs = ", plus 1 line of "--". matches will come from the generated grpc.sln
while read p ; do
mkdir -p templates/vsprojects/$p
echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$p'", libs)}' > templates/vsprojects/$p/$p.vcxproj.template
line_number=$((line_number + 1))
if [ "$line_number" -gt "4" ]; then
line_number=1;
fi
echo $line_number
echo $p
if [ "$line_number" -eq "1" ]; then
project_name=$(echo "$p" | cut -d\" -f 4) #sed: extract line N only; cut with delimiter: ". select only field 4
fi
if [ "$line_number" -eq "3" ]; then
lib_setting=$(echo "$p" | cut -d\" -f 2) #
echo "project_name"
echo $project_name
echo "lib_setting"
echo $lib_setting
mkdir -p templates/vsprojects/$project_name
if [ "$lib_setting" = "True" ]; then
echo "lib: true"
echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$project_name'", libs)}' > templates/vsprojects/$project_name/$project_name.vcxproj.template
else
echo "lib: not true"
echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$project_name'", targets)}' > templates/vsprojects/$project_name/$project_name.vcxproj.template
fi
fi
# sleep .5 #for testing
done
./tools/buildgen/generate_projects.sh
./tools/buildgen/generate_projects-old.sh

@ -15,6 +15,13 @@ cpp_proj_type = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
%>\
% for project in solution_projects:
Project("${cpp_proj_type}") = "${project.name}", "${project.name}\${project.name}.vcxproj", "${project.vs_project_guid}"
ProjectSection(myProperties) = preProject
% if project.is_library:
lib = "True"
% else:
lib = "False"
% endif
EndProjectSection
% if project.get('deps', None):
ProjectSection(ProjectDependencies) = postProject
% for dep in project.get('deps', []):
@ -47,4 +54,4 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
</%def>\
</%def>\

@ -12,19 +12,21 @@
if t.name == name:
target = t
if not configuration_type and target:
print target.name
if target.build == 'test' or target.build == 'tool':
configuration_type = 'Application'
if not configuration_type:
configuration_type = 'StaticLibrary'
if not project_guid:
project_guid = project.vs_project_guid
if target.build == 'test' and target.language == 'c++':
props.extend(['cpptest'])
if configuration_type == 'Application':
print target.build
if target.build == 'protoc':
props.extend(['protoc'])
else:
props.extend(['winsock', 'protobuf', 'zlib', 'openssl'])
if target.language == 'c++':
props.extend(['protobuf'])
props.extend(['global'])
%>\
<?xml version="1.0" encoding="utf-8"?>
@ -113,6 +115,13 @@ ${gen_package_props(packages)}\
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>${name}</TargetName>
% if "zlib" in packages:
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
<Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
% endif
% if "openssl" in packages:
<Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
% endif
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>${name}</TargetName>
@ -200,8 +209,20 @@ ${gen_package_props(packages)}\
% if project.get('src',[]):
<ItemGroup>
% for src_name in project.src:
% if src_name.endswith(".proto"):
<% src_name_parts = src_name.split(".") %>\
<ClCompile Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".pb.cc")}">
</ClCompile>
<ClInclude Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".pb.h")}">
</ClInclude>
<ClCompile Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".grpc.pb.cc")}">
</ClCompile>
<ClInclude Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".grpc.pb.h")}">
</ClInclude>
% else:
<ClCompile Include="${get_repo_root()}\${to_windows_path(src_name)}">
</ClCompile>
% endif
% endfor
</ItemGroup>
% elif configuration_type != 'StaticLibrary':
@ -230,4 +251,4 @@ ${gen_package_targets(packages)}\
</ImportGroup>
${gen_package_ensure(packages)}\
</Project>
</%def>\
</%def>\

@ -0,0 +1,124 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "test/core/end2end/end2end_tests.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "src/core/channel/client_channel.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/http_server_filter.h"
#include "src/core/support/string.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
typedef struct fullstack_fixture_data {
char *localaddr;
} fullstack_fixture_data;
static int unique = 1;
static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
grpc_channel_args *client_args, grpc_channel_args *server_args) {
grpc_end2end_test_fixture f;
fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
memset(&f, 0, sizeof(f));
gpr_asprintf(&ffd->localaddr, "unix:/tmp/grpc_fullstack_test.%d.%d", getpid(),
unique++);
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create();
return f;
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
}
void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *server_args) {
fullstack_fixture_data *ffd = f->fixture_data;
if (f->server) {
grpc_server_destroy(f->server);
}
f->server = grpc_server_create(server_args);
grpc_server_register_completion_queue(f->server, f->cq);
GPR_ASSERT(grpc_server_add_http2_port(f->server, ffd->localaddr));
grpc_server_start(f->server);
}
void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
fullstack_fixture_data *ffd = f->fixture_data;
gpr_free(ffd->localaddr);
gpr_free(ffd);
}
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/fullstack_uds", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
};
int main(int argc, char **argv) {
size_t i;
grpc_platform_become_multipoller = grpc_poll_become_multipoller;
grpc_test_init(argc, argv);
grpc_init();
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
grpc_end2end_tests(configs[i]);
}
grpc_shutdown();
return 0;
}

@ -36,38 +36,42 @@ import simplejson
import collections
FixtureOptions = collections.namedtuple('FixtureOptions', 'secure platforms')
default_unsecure_fixture_options = FixtureOptions(False, ['windows', 'posix'])
default_secure_fixture_options = FixtureOptions(True, ['windows', 'posix'])
FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack secure platforms')
default_unsecure_fixture_options = FixtureOptions(True, False, ['windows', 'posix'])
socketpair_unsecure_fixture_options = FixtureOptions(False, False, ['windows', 'posix'])
default_secure_fixture_options = FixtureOptions(True, True, ['windows', 'posix'])
# maps fixture name to whether it requires the security library
END2END_FIXTURES = {
'chttp2_fake_security': default_secure_fixture_options,
'chttp2_fullstack': default_unsecure_fixture_options,
'chttp2_fullstack_compression': default_unsecure_fixture_options,
'chttp2_fullstack_with_poll': FixtureOptions(False, ['posix']),
'chttp2_fullstack_uds_posix': FixtureOptions(False, ['posix']),
'chttp2_fullstack': default_unsecure_fixture_options,
'chttp2_fullstack_uds_posix': FixtureOptions(True, False, ['posix']),
'chttp2_fullstack_uds_posix_with_poll': FixtureOptions(True, False, ['posix']),
'chttp2_fullstack_with_poll': FixtureOptions(True, False, ['posix']),
'chttp2_simple_ssl_fullstack': default_secure_fixture_options,
'chttp2_simple_ssl_fullstack_with_poll': FixtureOptions(True, ['posix']),
'chttp2_simple_ssl_fullstack_with_poll': FixtureOptions(True, True, ['posix']),
'chttp2_simple_ssl_with_oauth2_fullstack': default_secure_fixture_options,
'chttp2_socket_pair': default_unsecure_fixture_options,
'chttp2_socket_pair_one_byte_at_a_time': default_unsecure_fixture_options,
'chttp2_socket_pair_with_grpc_trace': default_unsecure_fixture_options,
'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options,
'chttp2_socket_pair': socketpair_unsecure_fixture_options,
'chttp2_socket_pair_with_grpc_trace': socketpair_unsecure_fixture_options,
}
TestOptions = collections.namedtuple('TestOptions', 'flaky secure')
default_test_options = TestOptions(False, False)
TestOptions = collections.namedtuple('TestOptions', 'needs_fullstack flaky secure')
default_test_options = TestOptions(False, False, False)
connectivity_test_options = TestOptions(True, False, False)
# maps test names to options
END2END_TESTS = {
'bad_hostname': default_test_options,
'cancel_after_accept': default_test_options,
'cancel_after_accept_and_writes_closed': default_test_options,
'cancel_after_accept': default_test_options,
'cancel_after_invoke': default_test_options,
'cancel_before_invoke': default_test_options,
'cancel_in_a_vacuum': default_test_options,
'census_simple_request': default_test_options,
'disappearing_server': default_test_options,
'channel_connectivity': connectivity_test_options,
'disappearing_server': connectivity_test_options,
'early_server_shutdown_finishes_inflight_calls': default_test_options,
'early_server_shutdown_finishes_tags': default_test_options,
'empty_batch': default_test_options,
@ -79,21 +83,28 @@ END2END_TESTS = {
'ping_pong_streaming': default_test_options,
'registered_call': default_test_options,
'request_response_with_binary_metadata_and_payload': default_test_options,
'request_response_with_trailing_metadata_and_payload': default_test_options,
'request_response_with_metadata_and_payload': default_test_options,
'request_response_with_payload_and_call_creds': TestOptions(needs_fullstack=False, flaky=False, secure=True),
'request_response_with_payload': default_test_options,
'request_response_with_payload_and_call_creds': TestOptions(flaky=False, secure=True),
'request_with_large_metadata': default_test_options,
'request_with_payload': default_test_options,
'request_response_with_trailing_metadata_and_payload': default_test_options,
'request_with_compressed_payload': default_test_options,
'request_with_flags': default_test_options,
'request_with_large_metadata': default_test_options,
'request_with_payload': default_test_options,
'server_finishes_request': default_test_options,
'simple_delayed_request': default_test_options,
'simple_delayed_request': connectivity_test_options,
'simple_request': default_test_options,
'simple_request_with_high_initial_sequence_number': default_test_options,
}
def compatible(f, t):
if END2END_TESTS[t].needs_fullstack:
if not END2END_FIXTURES[f].fullstack:
return False
return True
def main():
sec_deps = [
'end2end_certs',
@ -157,7 +168,8 @@ def main():
'end2end_test_%s' % t] + sec_deps
}
for f in sorted(END2END_FIXTURES.keys())
for t in sorted(END2END_TESTS.keys())] + [
for t in sorted(END2END_TESTS.keys())
if compatible(f, t)] + [
{
'name': '%s_%s_unsecure_test' % (f, t),
'build': 'test',
@ -171,7 +183,7 @@ def main():
'end2end_test_%s' % t] + unsec_deps
}
for f in sorted(END2END_FIXTURES.keys()) if not END2END_FIXTURES[f].secure
for t in sorted(END2END_TESTS.keys()) if not END2END_TESTS[t].secure]}
for t in sorted(END2END_TESTS.keys()) if compatible(f, t) and not END2END_TESTS[t].secure]}
print simplejson.dumps(json, sort_keys=True, indent=2 * ' ')

@ -0,0 +1,123 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "test/core/end2end/end2end_tests.h"
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "test/core/end2end/cq_verifier.h"
static void *tag(gpr_intptr t) { return (void *)t; }
static void test_connectivity(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
grpc_connectivity_state state;
cq_verifier *cqv = cq_verifier_create(f.cq);
config.init_client(&f, NULL);
/* channels should start life in IDLE, and stay there */
GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 0) == GRPC_CHANNEL_IDLE);
gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100));
GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 0) == GRPC_CHANNEL_IDLE);
/* start watching for a change */
grpc_channel_watch_connectivity_state(
f.client, GRPC_CHANNEL_IDLE, &state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(1));
/* nothing should happen */
cq_verify_empty(cqv);
/* check that we're still in idle, and start connecting */
GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) == GRPC_CHANNEL_IDLE);
/* and now the watch should trigger */
cq_expect_completion(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(state == GRPC_CHANNEL_CONNECTING);
/* quickly followed by a transition to TRANSIENT_FAILURE */
grpc_channel_watch_connectivity_state(
f.client, GRPC_CHANNEL_CONNECTING, &state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(2));
cq_expect_completion(cqv, tag(2), 1);
cq_verify(cqv);
GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE);
gpr_log(GPR_DEBUG, "*** STARTING SERVER ***");
/* now let's bring up a server to connect to */
config.init_server(&f, NULL);
gpr_log(GPR_DEBUG, "*** STARTED SERVER ***");
/* we'll go through some set of transitions (some might be missed), until
READY is reached */
while (state != GRPC_CHANNEL_READY) {
grpc_channel_watch_connectivity_state(
f.client, state, &state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(3));
cq_expect_completion(cqv, tag(3), 1);
cq_verify(cqv);
GPR_ASSERT(state == GRPC_CHANNEL_READY || state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_TRANSIENT_FAILURE);
}
/* bring down the server again */
/* we should go immediately to TRANSIENT_FAILURE */
gpr_log(GPR_DEBUG, "*** SHUTTING DOWN SERVER ***");
grpc_channel_watch_connectivity_state(
f.client, GRPC_CHANNEL_READY, &state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(4));
grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
cq_expect_completion(cqv, tag(4), 1);
cq_expect_completion(cqv, tag(0xdead), 1);
cq_verify(cqv);
GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE);
/* cleanup server */
grpc_server_destroy(f.server);
gpr_log(GPR_DEBUG, "*** SHUTDOWN SERVER ***");
grpc_channel_destroy(f.client);
grpc_completion_queue_shutdown(f.cq);
grpc_completion_queue_destroy(f.cq);
config.tear_down_data(&f);
cq_verifier_destroy(cqv);
}
void grpc_end2end_tests(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
test_connectivity(config);
}

@ -199,7 +199,6 @@ static void disappearing_server_test(grpc_end2end_test_config config) {
}
void grpc_end2end_tests(grpc_end2end_test_config config) {
if (config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION) {
disappearing_server_test(config);
}
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
disappearing_server_test(config);
}

@ -207,8 +207,7 @@ static void test_simple_delayed_request_long(grpc_end2end_test_config config) {
}
void grpc_end2end_tests(grpc_end2end_test_config config) {
if (config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION) {
test_simple_delayed_request_short(config);
test_simple_delayed_request_long(config);
}
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
test_simple_delayed_request_short(config);
test_simple_delayed_request_long(config);
}

@ -84,7 +84,7 @@ char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds) {
gpr_mu_lock(GRPC_POLLSET_MU(&request.pollset));
while (!request.is_done)
grpc_pollset_work(&request.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
grpc_pollset_work(&request.pollset, gpr_inf_future(GPR_CLOCK_MONOTONIC));
gpr_mu_unlock(GRPC_POLLSET_MU(&request.pollset));
grpc_pollset_shutdown(&request.pollset, do_nothing, NULL);

@ -47,7 +47,7 @@ class CredentialsTest : public ::testing::Test {
TEST_F(CredentialsTest, InvalidServiceAccountCreds) {
std::shared_ptr<Credentials> bad1 = ServiceAccountCredentials("", "", 1);
EXPECT_EQ(static_cast<Credentials *>(nullptr), bad1.get());
EXPECT_EQ(static_cast<Credentials*>(nullptr), bad1.get());
}
} // namespace testing

@ -528,7 +528,7 @@ TEST_F(End2endTest, DiffPackageServices) {
// rpc and stream should fail on bad credentials.
TEST_F(End2endTest, BadCredentials) {
std::shared_ptr<Credentials> bad_creds = ServiceAccountCredentials("", "", 1);
EXPECT_EQ(static_cast<Credentials *>(nullptr), bad_creds.get());
EXPECT_EQ(static_cast<Credentials*>(nullptr), bad_creds.get());
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), bad_creds, ChannelArguments());
std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub(

@ -0,0 +1,76 @@
#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
if [ "x$TEST" = "x" ] ; then
TEST=false
fi
cd `dirname $0`/../..
mako_renderer=tools/buildgen/mako_renderer.py
if [ "x$TEST" != "x" ] ; then
tools/buildgen/build-cleaner.py build.json
fi
. tools/buildgen/generate_build_additions.sh
global_plugins=`find ./tools/buildgen/plugins -name '*.py' |
sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
for dir in . ; do
local_plugins=`find $dir/templates -name '*.py' |
sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
plugins="$global_plugins $local_plugins"
find -L $dir/templates -type f -and -name *.template | while read file ; do
out=${dir}/${file#$dir/templates/} # strip templates dir prefix
out=${out%.*} # strip template extension
echo "generating file: $out"
json_files="build.json $gen_build_files"
data=`for i in $json_files ; do echo $i ; done | awk ' { printf "-d %s ", $0 } '`
if [ "x$TEST" = "xtrue" ] ; then
actual_out=$out
out=`mktemp /tmp/gentXXXXXX`
fi
mkdir -p `dirname $out` # make sure dest directory exist
$mako_renderer $plugins $data -o $out $file
if [ "x$TEST" = "xtrue" ] ; then
diff -q $out $actual_out
rm $out
fi
done
done
rm $gen_build_files

@ -70,7 +70,7 @@ def mako_plugin(dictionary):
if project.get('vs_project_guid', None)]
projects = [project for project in projects
if project['language'] != 'c++' or project['build'] == 'all' or project['build'] == 'protoc']
if project['language'] != 'c++' or project['build'] == 'all' or project['build'] == 'protoc' or (project['language'] == 'c++' and (project['build'] == 'test' or project['build'] == 'private'))]
project_dict = dict([(p['name'], p) for p in projects])

@ -978,6 +978,7 @@ src/core/surface/call.c \
src/core/surface/call_details.c \
src/core/surface/call_log_batch.c \
src/core/surface/channel.c \
src/core/surface/channel_connectivity.c \
src/core/surface/channel_create.c \
src/core/surface/completion_queue.c \
src/core/surface/event_string.c \

@ -34,8 +34,8 @@ log_link=https://pantheon.corp.google.com/m/cloudstorage/b/stoked-keyword-656-ou
main() {
source grpc_docker.sh
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
auth_test_cases=(service_account_creds compute_engine_creds jwt_token_creds)
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response empty_stream timeout_on_sleeping_server)
auth_test_cases=(service_account_creds compute_engine_creds jwt_token_creds oauth2_auth_token per_rpc_creds)
clients=(cxx java go ruby node csharp_mono csharp_dotnet python php)
for test_case in "${test_cases[@]}"
do

@ -508,7 +508,12 @@ grpc_cloud_prod_auth_test_args() {
grpc_gen_test_cmd="grpc_cloud_prod_auth_"
[[ -n $1 ]] && { # test_case
test_case=$1
grpc_gen_test_cmd+="$1"
test_command="service_account_creds"
if [ "$test_case" == "compute_engine_creds" ]
then
test_command="compute_engine_creds"
fi
grpc_gen_test_cmd+=$test_command
shift
} || {
echo "$FUNCNAME: missing arg: test_case" 1>&2

@ -37,7 +37,7 @@ fail_log_link=https://pantheon.corp.google.com/m/cloudstorage/b/stoked-keyword-6
main() {
source grpc_docker.sh
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response empty_stream timeout_on_sleeping_server)
clients=(cxx java go ruby node python csharp_mono php)
servers=(cxx java go ruby node python csharp_mono)
for test_case in "${test_cases[@]}"

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
@ -31,6 +31,8 @@
# This script is invoked by Jenkins and triggers a test run based on
# env variable settings.
#
# Bootstrap into bash
[ -z $1 ] && exec bash $0 bootstrapped
# Setting up rvm environment BEFORE we set -ex.
[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
# To prevent cygwin bash complaining about empty lines ending with \r
@ -90,7 +92,9 @@ then
docker cp $DOCKER_CID:/var/local/git/grpc/report.xml $git_root
sleep 4
docker rm $DOCKER_CID || true
elif [ "$platform" == "interop" ]
then
python tools/run_tests/run_interops.py --language=$language
elif [ "$platform" == "windows" ]
then
echo "building $language on Windows"
@ -103,11 +107,18 @@ then
/cygdrive/c/nuget/nuget.exe restore src/csharp/Grpc.sln
python tools/run_tests/run_tests.py -t -l $language -x report.xml || true
elif [ "$platform" == "macos" ]
then
echo "building $language on MacOS"
./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
elif [ "$platform" == "freebsd" ]
then
echo "building $language on FreeBSD"
MAKE=gmake ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
else
echo "Unknown platform $platform"
exit 1

@ -206,7 +206,7 @@ class Job(object):
do_newline=self._newline_on_success or self._travis)
if self._bin_hash:
update_cache.finished(self._spec.identity(), self._bin_hash)
elif self._state == _RUNNING and time.time() - self._start > 600:
elif self._state == _RUNNING and time.time() - self._start > 900:
self._tempfile.seek(0)
stdout = self._tempfile.read()
filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))

@ -0,0 +1,36 @@
import argparse
import xml.etree.cElementTree as ET
import jobset
argp = argparse.ArgumentParser(description='Run interop tests.')
argp.add_argument('-l', '--language',
choices=['build_only', 'c++'],
nargs='+',
default=['build_only'])
args = argp.parse_args()
# build job
build_steps = 'tools/run_tests/run_interops_build.sh'
build_job = jobset.JobSpec(cmdline=build_steps, shortname='build')
# test jobs
_TESTS = ['large_unary', 'empty_unary', 'ping_pong', 'client_streaming', 'server_streaming']
jobs = []
jobNumber = 0
for lang in args.language:
for test in _TESTS:
test_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_test.sh', '%s' % lang, '%s' % test], shortname=test)
jobs.append(test_job)
jobNumber+=1
root = ET.Element('testsuites')
testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests')
# always do the build of docker first, and then all the tests can run in parallel
jobset.run([build_job], maxjobs=1, xml_report=testsuite)
jobset.run(jobs, maxjobs=jobNumber, xml_report=testsuite)
tree = ET.ElementTree(root)
tree.write('report.xml', encoding='UTF-8')

@ -0,0 +1,47 @@
#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
#clean up any old docker files and start mirroring repository if not started already
sudo docker rmi -f grpc/cxx || true
sudo docker rmi -f grpc/base || true
sudo docker rmi -f 0.0.0.0:5000/grpc/base || true
sudo docker run -d -e GCS_BUCKET=docker-interop-images -e STORAGE_PATH=/admin/docker_images -p 5000:5000 google/docker-registry || true
#prepare building by pulling down base images and necessary files
sudo docker pull 0.0.0.0:5000/grpc/base
sudo docker tag -f 0.0.0.0:5000/grpc/base grpc/base
gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_cxx
gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_cxx
#build docker file, add more languages later
sudo docker build --no-cache -t grpc/cxx tools/dockerfile/grpc_cxx

@ -0,0 +1,43 @@
#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
language=$1
test_case=$2
set -e
if [ "$language" = "c++" ]
then
sudo docker run grpc/cxx /var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots --server_host_override=grpc-test.sandbox.google.com --server_host=grpc-test.sandbox.google.com --server_port=443 --test_case=$test_case
else
echo "interop testss not added for $language"
exit 1
fi

@ -346,7 +346,7 @@ _CONFIGS = {
'dbg': SimpleConfig('dbg'),
'opt': SimpleConfig('opt'),
'tsan': SimpleConfig('tsan', environ={
'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1'}),
'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
'msan': SimpleConfig('msan'),
'ubsan': SimpleConfig('ubsan'),
'asan': SimpleConfig('asan', environ={
@ -458,7 +458,7 @@ if platform.system() == 'Windows':
cwd='vsprojects', shell=True)
else:
def make_jobspec(cfg, targets):
return jobset.JobSpec(['make',
return jobset.JobSpec([os.getenv('MAKE', 'make'),
'-j', '%d' % (multiprocessing.cpu_count() + 1),
'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
args.slowdown,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -19,19 +19,62 @@ After that, you can build the solution using one of these options:
1. open `grpc.sln` with Visual Studio and hit "Build".
2. build from commandline using `msbuild grpc.sln /p:Configuration=Debug`
#Testing
#C/C++ Test Dependencies
* gtest isn't available as a git repo like the other dependencies. download it and add it to `/third_party/gtest/` (the folder will end up with `/build-aux/`, `/cmake/`, `/codegear/`, etc. folders in it).
* if using vs2013: open/import the gtest solution in `/msvc/`, and save over the first solution (you will have to change it from read-only). change all projects to use `/MDd` (Property Pages - C/C++ - Code Generation - Runtime Library) and build. This is a "multithreaded debug" setting and it needs to match grpc.
* build all
* open protobuf solution in `/third_party/protobuf/vsprojects`
* if using vs2013: on import the gtest stuff will probably fail, I think the paths are interpreted wrong. it's ok.
* tests and test_plugin will fail when built. also ok
* build all
* gflags is automatically imported as a git submodule but it needs to have CMake run on it to be ready for a specific platform
* download [CMake](http://www.cmake.org/) windows installer; install
* open visual studio developer command prompt (not sure if dev command prompt is necessary)
* run `cmake <path to gtest directory>`
* this will build a `.sln` and fill up the `/third_party/gflags/include/gflags/` directory with headers
* build all
* install [NuGet](http://www.nuget.org)
* nuget should automatically bring in built versions of zlib and openssl when building grpc.sln (the versions in `/third_party/` are not used). If it doesn't work use `tools->nuget...->manage...`. The packages are put in `/vsprojects/packages/`
Use `run_tests.py`, that also supports Windows (with a bit limited experience).
```
> REM Run from repository root.
> python tools\run_tests\run_tests.py -l c
```
#C/C++ Test Solution/Project Build Steps
* A basic git version of grpc only has templates for non-test items. This checklist adds test items to grpc.sln and makes individual vs projects for them
* set up dependencies (above)
* add `"debug": true,` to the top of build.json. This is the base file for all build tracking, see [templates](https://github.com/grpc/grpc/tree/master/templates) for more information
* `"debug": true,` gets picked up by `/tools/buildgen/plugins/generate_vsprojects.py`. It tells the script to add visual studio GUIDs to all projects. Otherwise only the projects that already have GUIDs in build.json will be built
* run `/templates/vsprojects/generate_debug_projects.sh` to make debug templates/projects. This runs a regular visual studio buildgen process, which creates the `.sln` file with all of the new debug projects, then uses git diff to find the new project names from the `.sln` that need templates added. It builds the new templates based on the diff, then re-runs the visual studio buildgen, which builds the vs projects for each of the new debug targets
* copy over the `/vsprojects/` folder to your windows build setup (assuming this was built on linux in order to have easy access to python/mako and shell scripts)
* run `/templates/vsprojects/build_test_protos.sh`
* this builds all `.proto` files in `/test/` in-place. there might be a better place to put them that mirrors what happens in the linux build process (todo)
* each `.proto` file gets built into a `.grpc.pb.cc`, .`grpc.pb.h`, `.pb.cc`, and `.pb.h`. These are included in each test project in lieu of the `.proto` includes specified in `build.json`. This substitution is done by `/templates/vsprojects/vcxproj_defs.include`
* copy over the `/test/` folder in order to get the new files (assuming this was built on linux in order to have an easy protobuf+grpc plugin installation)
Also, you can `make.bat` directly to build and run gRPC tests.
```
> REM Run from this directory.
> make.bat alarm_test
```
#Making and running tests with `/tools/run_tests/run_tests.py` or `/vsprojects/make.bat`
`run_tests.py` and `make.bat` both rely on `/vsprojects/grpc.mak`, an NMAKE script that includes C/C++ tests in addition to the base grpc projects. It builds the base projects by calling grpc.sln, but most things are built with a command line similar to a makefile workflow.
arguments for `/vsprojects/make.bat`:
* no options or `all` or `buildtests`: builds all tests
* `buildtests_c`: just c tests
* `buildtests_cxx`: just c++ tests
* names of individual tests: just those tests (example: `make.bat gpr_string_test`)
using `run_tests.py` on windows:
* when `run_tests.py` detects that it's running on windows it calls `make.bat` to build the tests and expects to find tests in `/vsprojects/test_bins/`
`run_tests.py` options:
* `run_tests.py --help`
* `run_tests.py -l c`: run c language tests
* `run_tests.py -l c++`: run c++ language tests
* note: `run_tests.py` doesn't normally show build steps, so if a build fails it is best to fall back to `make.bat`
* if `make.bat` fails, it might be easier to open up the `.sln` file in the visual studio gui (see above for how to build the test projects) and build the offending test from its project file. The `.mak` and project file templates are slightly different, so it's possible that a project will build one way and not another. Please report this if it happens.
It can be helpful to disable the firewall when running tests so that 400 connection warnings don't pop up.
Individual tests can be run by directly running the executable in `/vsprojects/run_tests/` (this is `/bins/opt/` on linux). Many C tests have no output; they either pass or fail internally and communicate this with their exit code (`0=pass`, `nonzero=fail`)
`run_tests.py` will fail if it can't build something, so not-building tests are disabled with a "platforms = posix" note in build.json. The buildgen tools will not add a test to a windows build unless it is marked "windows" or has no platforms identified. As tests are ported they will get this mark removed.
# Building protoc plugins
For generating service stub code, gRPC relies on plugins for `protoc` (the protocol buffer compiler). The solution `grpc_protoc_plugins.sln` allows you to build

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\third_party\protobuf\src;$(ProjectDir)\..\..\third_party\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>EnableAllWarnings</WarningLevel>
</ClCompile>
<Link>
<AdditionalDependencies>grpc++_test_util.lib;grpc_test_util.lib;gpr_test_util.lib;gtestd.lib;gflags.lib;shlwapi.lib;gpr.lib;grpc.lib;grpc++.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)\..\..\third_party\gtest\msvc\gtest\Debug;$(ProjectDir)\..\..\third_party\gflags\lib\Debug;$(ProjectDir)\..\Debug;$(ProjectDir)\..\packages\grpc.dependencies.openssl.1.0.2.2\build\native\lib\$(PlatformToolset)\$(Platform)\$(Configuration)\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

@ -5,10 +5,10 @@
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\third_party\protobuf\src;$(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\third_party\protobuf\src;$(ProjectDir)\..\packages\grpc.dependencies.openssl.1.0.2.2\build\native\include;$(ProjectDir)\..\..\third_party\gflags\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>EnableAllWarnings</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
</Project>

@ -465,6 +465,8 @@
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel.c">
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_connectivity.c">
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_create.c">
</ClCompile>
<ClCompile Include="..\..\src\core\surface\completion_queue.c">

@ -289,6 +289,9 @@
<ClCompile Include="..\..\src\core\surface\channel.c">
<Filter>src\core\surface</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_connectivity.c">
<Filter>src\core\surface</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_create.c">
<Filter>src\core\surface</Filter>
</ClCompile>

@ -400,6 +400,8 @@
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel.c">
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_connectivity.c">
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_create.c">
</ClCompile>
<ClCompile Include="..\..\src\core\surface\completion_queue.c">

@ -220,6 +220,9 @@
<ClCompile Include="..\..\src\core\surface\channel.c">
<Filter>src\core\surface</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_connectivity.c">
<Filter>src\core\surface</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\surface\channel_create.c">
<Filter>src\core\surface</Filter>
</ClCompile>

@ -5,6 +5,7 @@ setlocal
@rem Set VS variables (uses Visual Studio 2013)
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
nmake /f Grpc.mak %*
@rem /K: continue on error
nmake /K /f Grpc.mak %*
exit /b %ERRORLEVEL%
endlocal
endlocal

Loading…
Cancel
Save