aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Vijay Pai <vpai@google.com>2016-06-15 22:57:21 -0700
committerGravatar Vijay Pai <vpai@google.com>2016-06-15 22:57:21 -0700
commitb9e927afcc689edaa5c02613a69fd9ceb944ec5b (patch)
tree338945681c588bbce751c82575ceb9b8f9466d59 /src/core
parent20bf126da605e3c765ddc494ce92de3a7ff32795 (diff)
parentfa9b7c1bc6488be17d18007f45c57dac39ea5b79 (diff)
Merge branch 'master' into wheezy
Diffstat (limited to 'src/core')
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c42
-rw-r--r--src/core/ext/load_reporting/load_reporting.c3
-rw-r--r--src/core/ext/resolver/dns/native/dns_resolver.c3
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c95
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2.c7
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c82
-rw-r--r--src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c7
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.c232
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.h66
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c98
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h3
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c10
-rw-r--r--src/core/lib/channel/channel_args.c23
-rw-r--r--src/core/lib/channel/channel_args.h2
-rw-r--r--src/core/lib/channel/channel_stack.c2
-rw-r--r--src/core/lib/channel/channel_stack.h3
-rw-r--r--src/core/lib/channel/channel_stack_builder.c4
-rw-r--r--src/core/lib/channel/compress_filter.c43
-rw-r--r--src/core/lib/channel/compress_filter.h6
-rw-r--r--src/core/lib/channel/http_client_filter.c13
-rw-r--r--src/core/lib/channel/http_client_filter.h2
-rw-r--r--src/core/lib/compression/compression.c (renamed from src/core/lib/compression/compression_algorithm.c)44
-rw-r--r--src/core/lib/iomgr/iomgr.c9
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.c10
-rw-r--r--src/core/lib/iomgr/socket_utils_posix.h8
-rw-r--r--src/core/lib/iomgr/udp_server.c14
-rw-r--r--src/core/lib/support/log_linux.c4
-rw-r--r--src/core/lib/support/string.c10
-rw-r--r--src/core/lib/support/string.h4
-rw-r--r--src/core/lib/surface/call.c319
-rw-r--r--src/core/lib/surface/call_log_batch.c2
-rw-r--r--src/core/lib/surface/channel.c32
-rw-r--r--src/core/lib/surface/channel.h4
-rw-r--r--src/core/lib/transport/metadata.c4
34 files changed, 1021 insertions, 189 deletions
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 8645333c8e..40dd7c5940 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -31,6 +31,34 @@
*
*/
+/** Round Robin Policy.
+ *
+ * This policy keeps:
+ * - A circular list of ready (connected) subchannels, the *readylist*. An empty
+ * readylist consists solely of its root (dummy) node.
+ * - A pointer to the last element picked from the readylist, the *lastpick*.
+ * Initially set to point to the readylist's root.
+ *
+ * Behavior:
+ * - When a subchannel connects, it's *prepended* to the readylist's root node.
+ * Ie, if readylist = A <-> B <-> ROOT <-> C
+ * ^ ^
+ * |____________________|
+ * and subchannel D becomes connected, the addition of D to the readylist
+ * results in readylist = A <-> B <-> D <-> ROOT <-> C
+ * ^ ^
+ * |__________________________|
+ * - When a subchannel disconnects, it's removed from the readylist. If the
+ * subchannel being removed was the most recently picked, the *lastpick*
+ * pointer moves to the removed node's previous element. Note that if the
+ * readylist only had one element, this is still legal, as the lastpick would
+ * point to the dummy root node, for an empty readylist.
+ * - Upon picking, *lastpick* is updated to point to the returned (connected)
+ * subchannel. Note that it's possible that the selected subchannel becomes
+ * disconnected in the interim between the selection and the actual usage of
+ * the subchannel by the caller.
+ */
+
#include <string.h>
#include <grpc/support/alloc.h>
@@ -173,9 +201,7 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
return;
}
if (node == p->ready_list_last_pick) {
- /* If removing the lastly picked node, reset the last pick pointer to the
- * dummy root of the list */
- p->ready_list_last_pick = &p->ready_list;
+ p->ready_list_last_pick = p->ready_list_last_pick->prev;
}
/* removing last item */
@@ -307,7 +333,7 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
p->started_picking = 1;
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
+ gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%" PRIuPTR, p,
p->num_subchannels);
}
@@ -345,8 +371,8 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
*target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG,
- "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
- selected->subchannel, selected);
+ "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)", *target,
+ selected);
}
/* only advance the last picked pointer if the selection was used */
advance_last_picked_locked(p);
@@ -526,7 +552,7 @@ static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
-static grpc_lb_policy *create_round_robin(grpc_exec_ctx *exec_ctx,
+static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
grpc_lb_policy_factory *factory,
grpc_lb_policy_args *args) {
GPR_ASSERT(args->addresses != NULL);
@@ -582,7 +608,7 @@ static grpc_lb_policy *create_round_robin(grpc_exec_ctx *exec_ctx,
}
static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
- round_robin_factory_ref, round_robin_factory_unref, create_round_robin,
+ round_robin_factory_ref, round_robin_factory_unref, round_robin_create,
"round_robin"};
static grpc_lb_policy_factory round_robin_lb_policy_factory = {
diff --git a/src/core/ext/load_reporting/load_reporting.c b/src/core/ext/load_reporting/load_reporting.c
index 60082dbaaa..9e4d32676f 100644
--- a/src/core/ext/load_reporting/load_reporting.c
+++ b/src/core/ext/load_reporting/load_reporting.c
@@ -76,7 +76,8 @@ static bool is_load_reporting_enabled(const grpc_channel_args *a) {
if (a == NULL) return false;
for (size_t i = 0; i < a->num_args; i++) {
if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_LOAD_REPORTING)) {
- return a->args[i].value.pointer.p != NULL;
+ return a->args[i].type == GRPC_ARG_POINTER &&
+ a->args[i].value.pointer.p != NULL;
}
}
return false;
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 620ba4e2aa..5efc95e0fa 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -183,7 +183,8 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
gpr_timespec timeout = gpr_time_sub(next_try, now);
- gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d.%09d seconds",
+ gpr_log(GPR_DEBUG,
+ "dns resolution failed: retrying in %" PRId64 ".%09d seconds",
timeout.tv_sec, timeout.tv_nsec);
GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true;
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
new file mode 100644
index 0000000000..ca435c25ce
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_posix.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+#include <fcntl.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/transport.h"
+
+grpc_channel *grpc_insecure_channel_create_from_fd(
+ const char *target, int fd, const grpc_channel_args *args) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GRPC_API_TRACE("grpc_insecure_channel_create(target=%p, fd=%d, args=%p)", 3,
+ (target, fd, args));
+
+ grpc_arg default_authority_arg;
+ default_authority_arg.type = GRPC_ARG_STRING;
+ default_authority_arg.key = GRPC_ARG_DEFAULT_AUTHORITY;
+ default_authority_arg.value.string = "test.authority";
+ grpc_channel_args *final_args =
+ grpc_channel_args_copy_and_add(args, &default_authority_arg, 1);
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
+
+ grpc_endpoint *client =
+ grpc_tcp_create(grpc_fd_create(fd, "client"),
+ GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "fd-client");
+
+ grpc_transport *transport =
+ grpc_create_chttp2_transport(&exec_ctx, final_args, client, 1);
+ GPR_ASSERT(transport);
+ grpc_channel *channel = grpc_channel_create(
+ &exec_ctx, target, final_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
+ grpc_channel_args_destroy(final_args);
+ grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+
+ grpc_exec_ctx_finish(&exec_ctx);
+
+ return channel != NULL ? channel : grpc_lame_client_channel_create(
+ target, GRPC_STATUS_INTERNAL,
+ "Failed to create client channel");
+}
+
+#else // !GPR_SUPPORT_CHANNELS_FROM_FD
+
+grpc_channel *grpc_insecure_channel_create_from_fd(
+ const char *target, int fd, const grpc_channel_args *args) {
+ GPR_ASSERT(0);
+ return NULL;
+}
+
+#endif // GPR_SUPPORT_CHANNELS_FROM_FD
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index 0428bb1e3d..c95dd20d1d 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -111,13 +111,14 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
}
}
if (count == 0) {
- gpr_log(GPR_ERROR, "No address added out of total %d resolved",
+ gpr_log(GPR_ERROR, "No address added out of total %" PRIuPTR " resolved",
resolved->naddrs);
goto error;
}
if (count != resolved->naddrs) {
- gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
- count, resolved->naddrs);
+ gpr_log(GPR_ERROR,
+ "Only %d addresses added out of total %" PRIuPTR " resolved", count,
+ resolved->naddrs);
}
grpc_resolved_addresses_destroy(resolved);
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
new file mode 100644
index 0000000000..96bf4d6f30
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_posix.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/server.h"
+
+void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
+ grpc_completion_queue *cq,
+ int fd) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ char *name;
+ gpr_asprintf(&name, "fd:%d", fd);
+
+ grpc_endpoint *server_endpoint = grpc_tcp_create(
+ grpc_fd_create(fd, name), GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
+
+ gpr_free(name);
+
+ const grpc_channel_args *server_args = grpc_server_get_channel_args(server);
+ grpc_transport *transport = grpc_create_chttp2_transport(
+ &exec_ctx, server_args, server_endpoint, 0 /* is_client */);
+ grpc_endpoint_add_to_pollset(&exec_ctx, server_endpoint, grpc_cq_pollset(cq));
+ grpc_server_setup_transport(&exec_ctx, server, transport, NULL, server_args);
+ grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+#else // !GPR_SUPPORT_CHANNELS_FROM_FD
+
+void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
+ grpc_completion_queue *cq,
+ int fd) {
+ GPR_ASSERT(0);
+}
+
+#endif // GPR_SUPPORT_CHANNELS_FROM_FD
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index ebbefbcd89..e3437e5ed3 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -229,13 +229,14 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
}
}
if (count == 0) {
- gpr_log(GPR_ERROR, "No address added out of total %d resolved",
+ gpr_log(GPR_ERROR, "No address added out of total %" PRIuPTR " resolved",
resolved->naddrs);
goto error;
}
if (count != resolved->naddrs) {
- gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
- count, resolved->naddrs);
+ gpr_log(GPR_ERROR,
+ "Only %d addresses added out of total %" PRIuPTR " resolved", count,
+ resolved->naddrs);
/* if it's an error, don't we want to goto error; here ? */
}
grpc_resolved_addresses_destroy(resolved);
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.c b/src/core/ext/transport/chttp2/transport/bin_decoder.c
new file mode 100644
index 0000000000..2d90b01cd8
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -0,0 +1,232 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/support/string.h"
+
+static uint8_t decode_table[] = {
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 62, 0x40, 0x40, 0x40, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40};
+
+static const uint8_t tail_xtra[4] = {0, 0, 1, 2};
+
+static bool input_is_valid(uint8_t *input_ptr, size_t length) {
+ size_t i;
+
+ for (i = 0; i < length; ++i) {
+ if ((decode_table[input_ptr[i]] & 0xC0) != 0) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, invalid character '%c' in base64 "
+ "input.\n",
+ (char)(*input_ptr));
+ return false;
+ }
+ }
+ return true;
+}
+
+#define COMPOSE_OUTPUT_BYTE_0(input_ptr) \
+ (uint8_t)((decode_table[input_ptr[0]] << 2) | \
+ (decode_table[input_ptr[1]] >> 4))
+
+#define COMPOSE_OUTPUT_BYTE_1(input_ptr) \
+ (uint8_t)((decode_table[input_ptr[1]] << 4) | \
+ (decode_table[input_ptr[2]] >> 2))
+
+#define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
+ (uint8_t)((decode_table[input_ptr[2]] << 6) | decode_table[input_ptr[3]])
+
+bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx) {
+ size_t input_tail;
+
+ if (ctx->input_cur > ctx->input_end || ctx->output_cur > ctx->output_end) {
+ return false;
+ }
+
+ // Process a block of 4 input characters and 3 output bytes
+ while (ctx->input_end >= ctx->input_cur + 4 &&
+ ctx->output_end >= ctx->output_cur + 3) {
+ if (!input_is_valid(ctx->input_cur, 4)) return false;
+ ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+ ctx->output_cur[2] = COMPOSE_OUTPUT_BYTE_2(ctx->input_cur);
+ ctx->output_cur += 3;
+ ctx->input_cur += 4;
+ }
+
+ // Process the tail of input data
+ input_tail = (size_t)(ctx->input_end - ctx->input_cur);
+ if (input_tail == 4) {
+ // Process the input data with pad chars
+ if (ctx->input_cur[3] == '=') {
+ if (ctx->input_cur[2] == '=' && ctx->output_end >= ctx->output_cur + 1) {
+ if (!input_is_valid(ctx->input_cur, 2)) return false;
+ *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ ctx->input_cur += 4;
+ } else if (ctx->output_end >= ctx->output_cur + 2) {
+ if (!input_is_valid(ctx->input_cur, 3)) return false;
+ *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+ ;
+ ctx->input_cur += 4;
+ }
+ }
+
+ } else if (ctx->contains_tail && input_tail > 1) {
+ // Process the input data without pad chars, but constains_tail is set
+ if (ctx->output_end >= ctx->output_cur + tail_xtra[input_tail]) {
+ if (!input_is_valid(ctx->input_cur, input_tail)) return false;
+ switch (input_tail) {
+ case 3:
+ ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+ case 2:
+ ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ }
+ ctx->output_cur += tail_xtra[input_tail];
+ ctx->input_cur += input_tail;
+ }
+ }
+
+ return true;
+}
+
+gpr_slice grpc_chttp2_base64_decode(gpr_slice input) {
+ size_t input_length = GPR_SLICE_LENGTH(input);
+ size_t output_length = input_length / 4 * 3;
+ struct grpc_base64_decode_context ctx;
+ gpr_slice output;
+
+ if (input_length % 4 != 0) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, input of "
+ "grpc_chttp2_base64_decode has a length of %d, which is not a "
+ "multiple of 4.\n",
+ (int)input_length);
+ return gpr_empty_slice();
+ }
+
+ if (input_length > 0) {
+ uint8_t *input_end = GPR_SLICE_END_PTR(input);
+ if (*(--input_end) == '=') {
+ output_length--;
+ if (*(--input_end) == '=') {
+ output_length--;
+ }
+ }
+ }
+ output = gpr_slice_malloc(output_length);
+
+ ctx.input_cur = GPR_SLICE_START_PTR(input);
+ ctx.input_end = GPR_SLICE_END_PTR(input);
+ ctx.output_cur = GPR_SLICE_START_PTR(output);
+ ctx.output_end = GPR_SLICE_END_PTR(output);
+ ctx.contains_tail = false;
+
+ if (!grpc_base64_decode_partial(&ctx)) {
+ char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
+ gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
+ gpr_free(s);
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+ GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
+ GPR_ASSERT(ctx.input_cur == GPR_SLICE_END_PTR(input));
+ return output;
+}
+
+gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
+ size_t output_length) {
+ size_t input_length = GPR_SLICE_LENGTH(input);
+ gpr_slice output = gpr_slice_malloc(output_length);
+ struct grpc_base64_decode_context ctx;
+
+ // The length of a base64 string cannot be 4 * n + 1
+ if (input_length % 4 == 1) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, input of "
+ "grpc_chttp2_base64_decode_with_length has a length of %d, which "
+ "has a tail of 1 byte.\n",
+ (int)input_length);
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+
+ if (output_length > input_length / 4 * 3 + tail_xtra[input_length % 4]) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, output_length %d is longer "
+ "than the max possible output length %d.\n",
+ (int)output_length,
+ (int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+
+ ctx.input_cur = GPR_SLICE_START_PTR(input);
+ ctx.input_end = GPR_SLICE_END_PTR(input);
+ ctx.output_cur = GPR_SLICE_START_PTR(output);
+ ctx.output_end = GPR_SLICE_END_PTR(output);
+ ctx.contains_tail = true;
+
+ if (!grpc_base64_decode_partial(&ctx)) {
+ char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
+ gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
+ gpr_free(s);
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+ GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
+ GPR_ASSERT(ctx.input_cur <= GPR_SLICE_END_PTR(input));
+ return output;
+}
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
new file mode 100644
index 0000000000..b9d40c9b74
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
+
+#include <grpc/support/slice.h>
+#include <stdbool.h>
+
+struct grpc_base64_decode_context {
+ /* input/output: */
+ uint8_t *input_cur;
+ uint8_t *input_end;
+ uint8_t *output_cur;
+ uint8_t *output_end;
+ /* Indicate if the decoder should handle the tail of input data*/
+ bool contains_tail;
+};
+
+/* base64 decode a grpc_base64_decode_context util either input_end is reached
+ or output_end is reached. When input_end is reached, (input_end - input_cur)
+ is less than 4. When output_end is reached, (output_end - output_cur) is less
+ than 3. Returns false if decoding is failed. */
+bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx);
+
+/* base64 decode a slice with pad chars. Returns a new slice, does not take
+ ownership of the input. Returns an empty slice if decoding is failed. */
+gpr_slice grpc_chttp2_base64_decode(gpr_slice input);
+
+/* base64 decode a slice without pad chars, data length is needed. Returns a new
+ slice, does not take ownership of the input. Returns an empty slice if
+ decoding is failed. */
+gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
+ size_t output_length);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 046b395001..6e8640f1b3 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -47,6 +47,7 @@
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/lib/http/parser.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
@@ -107,7 +108,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
- grpc_status_code status);
+ grpc_status_code status,
+ gpr_slice *optional_message);
static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
@@ -161,6 +163,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(t->ep == NULL);
+ gpr_slice_unref(t->optional_drop_message);
+
gpr_slice_buffer_destroy(&t->global.qbuf);
gpr_slice_buffer_destroy(&t->writing.outbuf);
@@ -260,6 +264,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->parsing.deframe_state =
is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
t->writing.is_client = is_client;
+ t->optional_drop_message = gpr_empty_slice();
grpc_connectivity_state_init(
&t->channel_callback.state_tracker, GRPC_CHANNEL_READY,
is_client ? "client_transport" : "server_transport");
@@ -804,8 +809,10 @@ void grpc_chttp2_add_incoming_goaway(
gpr_free(msg);
gpr_slice_unref(goaway_text);
transport_global->seen_goaway = 1;
- connectivity_state_set(exec_ctx, transport_global, GRPC_CHANNEL_SHUTDOWN,
- "got_goaway");
+ /* lie: use transient failure from the transport to indicate goaway has been
+ * received */
+ connectivity_state_set(exec_ctx, transport_global,
+ GRPC_CHANNEL_TRANSIENT_FAILURE, "got_goaway");
}
static void maybe_start_some_streams(
@@ -859,7 +866,7 @@ static void maybe_start_some_streams(
grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
&stream_global)) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_UNAVAILABLE);
+ GRPC_STATUS_UNAVAILABLE, NULL);
}
}
@@ -936,7 +943,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (op->cancel_with_status != GRPC_STATUS_OK) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- op->cancel_with_status);
+ op->cancel_with_status, op->optional_close_message);
}
if (op->close_with_status != GRPC_STATUS_OK) {
@@ -957,10 +964,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (metadata_size > metadata_peer_limit) {
gpr_log(GPR_DEBUG,
"to-be-sent initial metadata size exceeds peer limit "
- "(%lu vs. %lu)",
+ "(%" PRIuPTR " vs. %" PRIuPTR ")",
metadata_size, metadata_peer_limit);
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
} else {
if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
stream_global->seen_error = true;
@@ -1012,10 +1019,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (metadata_size > metadata_peer_limit) {
gpr_log(GPR_DEBUG,
"to-be-sent trailing metadata size exceeds peer limit "
- "(%lu vs. %lu)",
+ "(%" PRIuPTR " vs. %" PRIuPTR ")",
metadata_size, metadata_peer_limit);
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
} else {
if (contains_non_ok_status(transport_global,
op->send_trailing_metadata)) {
@@ -1201,7 +1208,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
}
if (stream_global->exceeded_metadata_size) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
}
}
grpc_chttp2_incoming_metadata_buffer_publish(
@@ -1240,7 +1247,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
}
if (stream_global->exceeded_metadata_size) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
}
}
if (stream_global->all_incoming_byte_streams_finished) {
@@ -1303,7 +1310,8 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
- grpc_status_code status) {
+ grpc_status_code status,
+ gpr_slice *optional_message) {
if (!stream_global->read_closed || !stream_global->write_closed) {
if (stream_global->id != 0) {
gpr_slice_buffer_add(
@@ -1313,8 +1321,12 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
(uint32_t)grpc_chttp2_grpc_status_to_http2_error(status),
&stream_global->stats.outgoing));
}
+
+ if (optional_message) {
+ gpr_slice_ref(*optional_message);
+ }
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
- NULL);
+ optional_message);
}
if (status != GRPC_STATUS_OK && !stream_global->seen_error) {
stream_global->seen_error = true;
@@ -1524,8 +1536,12 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
void *user_data,
grpc_chttp2_stream_global *stream_global) {
+ grpc_chttp2_transport *transport = TRANSPORT_FROM_GLOBAL(transport_global);
cancel_from_api(user_data, transport_global, stream_global,
- GRPC_STATUS_UNAVAILABLE);
+ GRPC_STATUS_UNAVAILABLE,
+ GPR_SLICE_IS_EMPTY(transport->optional_drop_message)
+ ? NULL
+ : &transport->optional_drop_message);
}
static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
@@ -1601,6 +1617,29 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
}
}
+static bool try_http_parsing(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
+ grpc_http_parser parser;
+ size_t i = 0;
+ bool success = false;
+
+ grpc_http_parser_init(&parser);
+
+ for (; i < t->read_buffer.count &&
+ grpc_http_parser_parse(&parser, t->read_buffer.slices[i]);
+ i++)
+ ;
+ if (grpc_http_parser_eof(&parser) && parser.type == GRPC_HTTP_RESPONSE) {
+ success = true;
+ GRPC_CHTTP2_IF_TRACING(gpr_log(
+ GPR_DEBUG, "Trying to connect an http1.x server, received status:%d",
+ parser.http.response.status));
+ }
+
+ grpc_http_parser_destroy(&parser);
+ return success;
+}
+
static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_chttp2_transport *t = arg;
GPR_TIMER_BEGIN("reading_action.parse", 0);
@@ -1612,6 +1651,14 @@ static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
;
if (i != t->read_buffer.count) {
success = false;
+ gpr_slice_unref(t->optional_drop_message);
+ if (try_http_parsing(exec_ctx, t)) {
+ t->optional_drop_message = gpr_slice_from_copied_string(
+ "Connection dropped: received http1.x response");
+ } else {
+ t->optional_drop_message = gpr_slice_from_copied_string(
+ "Connection dropped: received unparseable response");
+ }
}
GPR_TIMER_END("reading_action.parse", 0);
grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked,
@@ -1972,10 +2019,13 @@ static char *format_flowctl_context_var(const char *context, const char *var,
int64_t val, uint32_t id,
char **scope) {
char *underscore_pos;
+ char *buf;
char *result;
if (context == NULL) {
*scope = NULL;
- gpr_asprintf(&result, "%s(%lld)", var, val);
+ gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
+ result = gpr_leftpad(buf, ' ', 40);
+ gpr_free(buf);
return result;
}
underscore_pos = strchr(context, '_');
@@ -1986,7 +2036,9 @@ static char *format_flowctl_context_var(const char *context, const char *var,
gpr_asprintf(scope, "%s[%d]", tmp, id);
gpr_free(tmp);
}
- gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val);
+ gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
+ result = gpr_leftpad(buf, ' ', 40);
+ gpr_free(buf);
return result;
}
@@ -2007,6 +2059,8 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
uint32_t stream_id, int64_t val1, int64_t val2) {
char *scope1;
char *scope2;
+ char *tmp_phase;
+ char *tmp_scope1;
char *label1 =
format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
char *label2 =
@@ -2014,14 +2068,18 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
char *clisvr = is_client ? "client" : "server";
char *prefix;
- gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, scope1);
+ tmp_phase = gpr_leftpad(phase, ' ', 8);
+ tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
+ gpr_asprintf(&prefix, "FLOW %s: %s %s ", phase, clisvr, scope1);
+ gpr_free(tmp_phase);
+ gpr_free(tmp_scope1);
switch (op) {
case GRPC_CHTTP2_FLOWCTL_MOVE:
GPR_ASSERT(samestr(scope1, scope2));
if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "%sMOVE % 40s <- % 40s giving %d", prefix, label1, label2,
+ "%sMOVE %s <- %s giving %" PRId64, prefix, label1, label2,
val1 + val2);
}
break;
@@ -2029,7 +2087,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
GPR_ASSERT(val2 >= 0);
if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2,
+ "%sCREDIT %s by %s giving %" PRId64, prefix, label1, label2,
val1 + val2);
}
break;
@@ -2037,7 +2095,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
GPR_ASSERT(val2 >= 0);
if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "%sDEBIT % 40s by % 40s giving %d", prefix, label1, label2,
+ "%sDEBIT %s by %s giving %" PRId64, prefix, label1, label2,
val1 - val2);
}
break;
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 5872fd8e0a..7f3339a620 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -383,6 +383,9 @@ struct grpc_chttp2_transport {
/** Transport op to be applied post-parsing */
grpc_transport_op *post_parsing_op;
+
+ /** Message explaining the reason of dropping connection */
+ gpr_slice optional_drop_message;
};
typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 4bd374b7fa..3c74258352 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -534,14 +534,14 @@ static grpc_chttp2_parse_error update_incoming_window(
grpc_chttp2_stream_parsing *stream_parsing) {
uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
if (incoming_frame_size > transport_parsing->incoming_window) {
- gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
+ gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %" PRId64,
transport_parsing->incoming_frame_size,
transport_parsing->incoming_window);
return GRPC_CHTTP2_CONNECTION_ERROR;
}
if (incoming_frame_size > stream_parsing->incoming_window) {
- gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
+ gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %" PRId64,
transport_parsing->incoming_frame_size,
stream_parsing->incoming_window);
return GRPC_CHTTP2_CONNECTION_ERROR;
@@ -649,7 +649,8 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
if (new_size > metadata_size_limit) {
if (!stream_parsing->exceeded_metadata_size) {
gpr_log(GPR_DEBUG,
- "received initial metadata size exceeds limit (%lu vs. %lu)",
+ "received initial metadata size exceeds limit (%" PRIuPTR
+ " vs. %" PRIuPTR ")",
new_size, metadata_size_limit);
stream_parsing->seen_error = true;
stream_parsing->exceeded_metadata_size = true;
@@ -695,7 +696,8 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
if (new_size > metadata_size_limit) {
if (!stream_parsing->exceeded_metadata_size) {
gpr_log(GPR_DEBUG,
- "received trailing metadata size exceeds limit (%lu vs. %lu)",
+ "received trailing metadata size exceeds limit (%" PRIuPTR
+ " vs. %" PRIuPTR ")",
new_size, metadata_size_limit);
stream_parsing->seen_error = true;
stream_parsing->exceeded_metadata_size = true;
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 569be4dc28..d53ce904a9 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -35,6 +35,7 @@
#include <grpc/grpc.h>
#include "src/core/lib/support/string.h"
+#include <grpc/compression.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
@@ -181,6 +182,7 @@ grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
grpc_channel_args *grpc_channel_args_set_compression_algorithm(
grpc_channel_args *a, grpc_compression_algorithm algorithm) {
+ GPR_ASSERT(algorithm < GRPC_COMPRESS_ALGORITHMS_COUNT);
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM;
@@ -200,7 +202,8 @@ static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
!strcmp(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
a->args[i].key)) {
*states_arg = &a->args[i].value.integer;
- return 1; /* GPR_TRUE */
+ **states_arg |= 0x1; /* forcefully enable support for no compression */
+ return 1;
}
}
}
@@ -214,10 +217,18 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
const int states_arg_found =
find_compression_algorithm_states_bitset(*a, &states_arg);
- if (states_arg_found) {
+ if (grpc_channel_args_get_compression_algorithm(*a) == algorithm &&
+ state == 0) {
+ char *algo_name = NULL;
+ GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name) != 0);
+ gpr_log(GPR_ERROR,
+ "Tried to disable default compression algorithm '%s'. The "
+ "operation has been ignored.",
+ algo_name);
+ } else if (states_arg_found) {
if (state != 0) {
GPR_BITSET((unsigned *)states_arg, algorithm);
- } else {
+ } else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned *)states_arg, algorithm);
}
} else {
@@ -229,7 +240,7 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
if (state != 0) {
GPR_BITSET((unsigned *)&tmp.value.integer, algorithm);
- } else {
+ } else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm);
}
result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
@@ -239,11 +250,11 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
return result;
}
-int grpc_channel_args_compression_algorithm_get_states(
+uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args *a) {
int *states_arg;
if (find_compression_algorithm_states_bitset(a, &states_arg)) {
- return *states_arg;
+ return (uint32_t)*states_arg;
} else {
return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 23c7b7b897..653d04f427 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -81,7 +81,7 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
*
* The i-th bit of the returned bitset corresponds to the i-th entry in the
* grpc_compression_algorithm enum. */
-int grpc_channel_args_compression_algorithm_get_states(
+uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args *a);
int grpc_channel_args_compare(const grpc_channel_args *a,
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 5c161652ac..bbba85d80b 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -106,6 +106,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
const grpc_channel_filter **filters,
size_t filter_count,
const grpc_channel_args *channel_args,
+ grpc_transport *optional_transport,
const char *name, grpc_channel_stack *stack) {
size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
@@ -127,6 +128,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
for (i = 0; i < filter_count; i++) {
args.channel_stack = stack;
args.channel_args = channel_args;
+ args.optional_transport = optional_transport;
args.is_first = i == 0;
args.is_last = i == (filter_count - 1);
elems[i].filter = filters[i];
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 3ca643c893..41dd4a0d8a 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -60,6 +60,8 @@ typedef struct grpc_call_stack grpc_call_stack;
typedef struct {
grpc_channel_stack *channel_stack;
const grpc_channel_args *channel_args;
+ /** Transport, iff it is known */
+ grpc_transport *optional_transport;
int is_first;
int is_last;
} grpc_channel_element_args;
@@ -198,6 +200,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
grpc_iomgr_cb_func destroy, void *destroy_arg,
const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
+ grpc_transport *optional_transport,
const char *name, grpc_channel_stack *stack);
/* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/channel/channel_stack_builder.c b/src/core/lib/channel/channel_stack_builder.c
index a8646c9565..eda4968f48 100644
--- a/src/core/lib/channel/channel_stack_builder.c
+++ b/src/core/lib/channel/channel_stack_builder.c
@@ -257,8 +257,8 @@ void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
// and initialize it
grpc_channel_stack_init(exec_ctx, initial_refs, destroy,
destroy_arg == NULL ? result : destroy_arg, filters,
- num_filters, builder->args, builder->name,
- channel_stack);
+ num_filters, builder->args, builder->transport,
+ builder->name, channel_stack);
// run post-initialization functions
i = 0;
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 7c8c1d6f31..32f4f8d37e 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -73,8 +73,8 @@ typedef struct call_data {
typedef struct channel_data {
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
- /** Compression options for the channel */
- grpc_compression_options compression_options;
+ /** Bitset of enabled algorithms */
+ uint32_t enabled_algorithms_bitset;
/** Supported compression algorithms */
uint32_t supported_compression_algorithms;
} channel_data;
@@ -96,9 +96,8 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
md_c_str);
calld->compression_algorithm = GRPC_COMPRESS_NONE;
}
- if (grpc_compression_options_is_algorithm_enabled(
- &channeld->compression_options, calld->compression_algorithm) ==
- 0) {
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset,
+ calld->compression_algorithm)) {
gpr_log(GPR_ERROR,
"Invalid compression algorithm: '%s' (previously disabled). "
"Ignoring.",
@@ -178,8 +177,8 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
const float savings_ratio = 1.0f - (float)after_size / (float)before_size;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name));
- gpr_log(GPR_DEBUG,
- "Compressed[%s] %d bytes vs. %d bytes (%.2f%% savings)",
+ gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR
+ " bytes (%.2f%% savings)",
algo_name, before_size, after_size, 100 * savings_ratio);
}
gpr_slice_buffer_swap(&calld->slices, &tmp);
@@ -189,10 +188,10 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
char *algo_name;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name));
- gpr_log(
- GPR_DEBUG,
- "Algorithm '%s' enabled but decided not to compress. Input size: %d",
- algo_name, calld->slices.length);
+ gpr_log(GPR_DEBUG,
+ "Algorithm '%s' enabled but decided not to compress. Input size: "
+ "%" PRIuPTR,
+ algo_name, calld->slices.length);
}
}
@@ -282,32 +281,26 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
channel_data *channeld = elem->channel_data;
- grpc_compression_algorithm algo_idx;
- grpc_compression_options_init(&channeld->compression_options);
- channeld->compression_options.enabled_algorithms_bitset =
- (uint32_t)grpc_channel_args_compression_algorithm_get_states(
- args->channel_args);
+ channeld->enabled_algorithms_bitset =
+ grpc_channel_args_compression_algorithm_get_states(args->channel_args);
channeld->default_compression_algorithm =
grpc_channel_args_get_compression_algorithm(args->channel_args);
/* Make sure the default isn't disabled. */
- if (!grpc_compression_options_is_algorithm_enabled(
- &channeld->compression_options,
- channeld->default_compression_algorithm)) {
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset,
+ channeld->default_compression_algorithm)) {
gpr_log(GPR_DEBUG,
"compression algorithm %d not enabled: switching to none",
channeld->default_compression_algorithm);
channeld->default_compression_algorithm = GRPC_COMPRESS_NONE;
}
- channeld->compression_options.default_compression_algorithm =
- channeld->default_compression_algorithm;
- channeld->supported_compression_algorithms = 0;
- for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
+ channeld->supported_compression_algorithms = 1; /* always support identity */
+ for (grpc_compression_algorithm algo_idx = 1;
+ algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
/* skip disabled algorithms */
- if (grpc_compression_options_is_algorithm_enabled(
- &channeld->compression_options, algo_idx) == 0) {
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset, algo_idx)) {
continue;
}
channeld->supported_compression_algorithms |= 1u << algo_idx;
diff --git a/src/core/lib/channel/compress_filter.h b/src/core/lib/channel/compress_filter.h
index 0ce5d08837..e4a2a829d5 100644
--- a/src/core/lib/channel/compress_filter.h
+++ b/src/core/lib/channel/compress_filter.h
@@ -34,9 +34,9 @@
#ifndef GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
#define GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
-#include "src/core/lib/channel/channel_stack.h"
+#include <grpc/impl/codegen/compression_types.h>
-#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request"
+#include "src/core/lib/channel/channel_stack.h"
extern int grpc_compression_trace;
@@ -48,7 +48,7 @@ extern int grpc_compression_trace;
* - Channel configuration, as established at channel creation time.
* - The metadata accompanying the outgoing data to be compressed. This is
* taken as a request only. We may choose not to honor it. The metadata key
- * is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY.
+ * is given by \a GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY.
*
* Compression can be disabled for concrete messages (for instance in order to
* prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 2245a52599..792f0d8ae6 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -38,6 +38,7 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/transport_impl.h"
#define EXPECTED_CONTENT_TYPE "application/grpc"
#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
@@ -199,7 +200,8 @@ static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
return GRPC_MDELEM_SCHEME_HTTP;
}
-static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
+static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args,
+ const char *transport_name) {
gpr_strvec v;
size_t i;
int is_first = 1;
@@ -221,8 +223,8 @@ static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
}
}
- gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
- grpc_version_string(), GPR_PLATFORM_STRING);
+ gpr_asprintf(&tmp, "%sgrpc-c/%s (%s; %s)", is_first ? "" : " ",
+ grpc_version_string(), GPR_PLATFORM_STRING, transport_name);
is_first = 0;
gpr_strvec_add(&v, tmp);
@@ -253,9 +255,12 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element_args *args) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(!args->is_last);
+ GPR_ASSERT(args->optional_transport != NULL);
chand->static_scheme = scheme_from_args(args->channel_args);
chand->user_agent = grpc_mdelem_from_metadata_strings(
- GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
+ GRPC_MDSTR_USER_AGENT,
+ user_agent_from_args(args->channel_args,
+ args->optional_transport->vtable->name));
}
/* Destructor for channel data */
diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/lib/channel/http_client_filter.h
index a884b36318..47081175ea 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/src/core/lib/channel/http_client_filter.h
@@ -1,5 +1,4 @@
/*
- *
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -39,6 +38,7 @@
/* Processes metadata on the client side for HTTP2 transports */
extern const grpc_channel_filter grpc_http_client_filter;
+/* Channel arg to override the http2 :scheme header */
#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/lib/compression/compression_algorithm.c b/src/core/lib/compression/compression.c
index 820871d579..54efb5e855 100644
--- a/src/core/lib/compression/compression_algorithm.c
+++ b/src/core/lib/compression/compression.c
@@ -125,6 +125,28 @@ grpc_mdelem *grpc_compression_encoding_mdelem(
return NULL;
}
+void grpc_compression_options_init(grpc_compression_options *opts) {
+ memset(opts, 0, sizeof(*opts));
+ /* all enabled by default */
+ opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
+}
+
+void grpc_compression_options_enable_algorithm(
+ grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+ GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+void grpc_compression_options_disable_algorithm(
+ grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+ GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+int grpc_compression_options_is_algorithm_enabled(
+ const grpc_compression_options *opts,
+ grpc_compression_algorithm algorithm) {
+ return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
+}
+
/* TODO(dgq): Add the ability to specify parameters to the individual
* compression algorithms */
grpc_compression_algorithm grpc_compression_algorithm_for_level(
@@ -180,25 +202,3 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level(
abort();
};
}
-
-void grpc_compression_options_init(grpc_compression_options *opts) {
- opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
- opts->default_compression_algorithm = GRPC_COMPRESS_NONE;
-}
-
-void grpc_compression_options_enable_algorithm(
- grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
- GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
-}
-
-void grpc_compression_options_disable_algorithm(
- grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
- GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
-}
-
-int grpc_compression_options_is_algorithm_enabled(
- const grpc_compression_options *opts,
- grpc_compression_algorithm algorithm) {
- if (algorithm >= GRPC_COMPRESS_ALGORITHMS_COUNT) return 0;
- return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
-}
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 60cef8ba77..89292a153e 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -96,7 +96,8 @@ void grpc_iomgr_shutdown(void) {
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time),
gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) {
if (g_root_object.next != &g_root_object) {
- gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
+ gpr_log(GPR_DEBUG,
+ "Waiting for %" PRIuPTR " iomgr objects to be destroyed",
count_objects());
}
last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
@@ -114,9 +115,9 @@ void grpc_iomgr_shutdown(void) {
if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) {
if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
if (g_root_object.next != &g_root_object) {
- gpr_log(GPR_DEBUG,
- "Failed to free %d iomgr objects before shutdown deadline: "
- "memory leaks are likely",
+ gpr_log(GPR_DEBUG, "Failed to free %" PRIuPTR
+ " iomgr objects before shutdown deadline: "
+ "memory leaks are likely",
count_objects());
dump_objects("LEAKED");
if (grpc_iomgr_abort_on_leaks()) {
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.c b/src/core/lib/iomgr/socket_utils_common_posix.c
index fa83ceef30..2147c86d4d 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.c
+++ b/src/core/lib/iomgr/socket_utils_common_posix.c
@@ -111,6 +111,16 @@ int grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
#endif
}
+int grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
+ return 0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size_bytes,
+ sizeof(buffer_size_bytes));
+}
+
+int grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
+ return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
+ sizeof(buffer_size_bytes));
+}
+
/* set a socket to close on exec */
int grpc_set_socket_cloexec(int fd, int close_on_exec) {
int oldflags = fcntl(fd, F_GETFD, 0);
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index a8f6e5e658..7e41d1c870 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -78,6 +78,14 @@ int grpc_set_socket_ip_pktinfo_if_possible(int fd);
If IPV6_RECVPKTINFO is not available, returns 1. */
int grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
+/* Tries to set the socket's send buffer to given size.
+ Returns 1 on success, 0 on failure. */
+int grpc_set_socket_sndbuf(int fd, int buffer_size_bytes);
+
+/* Tries to set the socket's receive buffer to given size.
+ Returns 1 on success, 0 on failure. */
+int grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes);
+
/* An enum to keep track of IPv4/IPv6 socket modes.
Currently, this information is only used when a socket is first created, but
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index 98ffccd59b..16150687d3 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -210,6 +210,8 @@ static int prepare_socket(int fd, const struct sockaddr *addr,
size_t addr_len) {
struct sockaddr_storage sockname_temp;
socklen_t sockname_len;
+ /* Set send/receive socket buffers to 1 MB */
+ int buffer_size_bytes = 1024 * 1024;
if (fd < 0) {
goto error;
@@ -239,6 +241,18 @@ static int prepare_socket(int fd, const struct sockaddr *addr,
goto error;
}
+ if (!grpc_set_socket_sndbuf(fd, buffer_size_bytes)) {
+ gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes",
+ buf_size_bytes);
+ goto error;
+ }
+
+ if (!grpc_set_socket_rcvbuf(fd, buffer_size_bytes)) {
+ gpr_log(GPR_ERROR, "Failed to set receive buffer size to %d bytes",
+ buf_size_bytes);
+ goto error;
+ }
+
return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
error:
diff --git a/src/core/lib/support/log_linux.c b/src/core/lib/support/log_linux.c
index ca04c022e3..508fae4eec 100644
--- a/src/core/lib/support/log_linux.c
+++ b/src/core/lib/support/log_linux.c
@@ -95,9 +95,9 @@ void gpr_default_log(gpr_log_func_args *args) {
strcpy(time_buffer, "error:strftime");
}
- gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
+ gpr_asprintf(&prefix, "%s%s.%09" PRId32 " %7ld %s:%d]",
gpr_log_severity_string(args->severity), time_buffer,
- (int)(now.tv_nsec), gettid(), display_file, args->line);
+ now.tv_nsec, gettid(), display_file, args->line);
fprintf(stderr, "%-60s %s\n", prefix, args->message);
gpr_free(prefix);
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
index a2ab6c5f1f..30c1e67647 100644
--- a/src/core/lib/support/string.c
+++ b/src/core/lib/support/string.c
@@ -194,6 +194,16 @@ int int64_ttoa(int64_t value, char *string) {
return i;
}
+char *gpr_leftpad(const char *str, char flag, size_t length) {
+ const size_t str_length = strlen(str);
+ const size_t out_length = str_length > length ? str_length : length;
+ char *out = gpr_malloc(out_length + 1);
+ memset(out, flag, out_length - str_length);
+ memcpy(out + out_length - str_length, str, str_length);
+ out[out_length] = 0;
+ return out;
+}
+
char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
return gpr_strjoin_sep(strs, nstrs, "", final_length);
}
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index ea58610914..2b6bb3eec6 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -83,6 +83,10 @@ int int64_ttoa(int64_t value, char *output);
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);
+/* Pad a string with flag characters. The given length specifies the minimum
+ field width. The input string is never truncated. */
+char *gpr_leftpad(const char *str, char flag, size_t length);
+
/* Join a set of strings, returning the resulting string.
Total combined length (excluding null terminator) is returned in total_length
if it is non-null. */
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index e899bc8098..c613f325dc 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -40,6 +40,7 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
@@ -52,7 +53,9 @@
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/transport.h"
/** The maximum number of concurrent batches possible.
Based upon the maximum number of individually queueable ops in the batch
@@ -154,8 +157,8 @@ struct grpc_call {
/* Call stats: only valid after trailing metadata received */
grpc_call_stats stats;
- /* Compression algorithm for the call */
- grpc_compression_algorithm compression_algorithm;
+ /* Compression algorithm for *incoming* data */
+ grpc_compression_algorithm incoming_compression_algorithm;
/* Supported encodings (compression algorithms), a bitset */
uint32_t encodings_accepted_by_peer;
@@ -214,6 +217,9 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description);
+static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
bool success);
static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
@@ -399,21 +405,27 @@ static void set_status_code(grpc_call *call, status_source source,
/* TODO(ctiller): what to do about the flush that was previously here */
}
-static void set_compression_algorithm(grpc_call *call,
- grpc_compression_algorithm algo) {
+static void set_incoming_compression_algorithm(
+ grpc_call *call, grpc_compression_algorithm algo) {
GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT);
- call->compression_algorithm = algo;
+ call->incoming_compression_algorithm = algo;
}
grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
grpc_call *call) {
grpc_compression_algorithm algorithm;
gpr_mu_lock(&call->mu);
- algorithm = call->compression_algorithm;
+ algorithm = call->incoming_compression_algorithm;
gpr_mu_unlock(&call->mu);
return algorithm;
}
+static grpc_compression_algorithm compression_algorithm_for_level_locked(
+ grpc_call *call, grpc_compression_level level) {
+ return grpc_compression_algorithm_for_level(level,
+ call->encodings_accepted_by_peer);
+}
+
uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
uint32_t flags;
gpr_mu_lock(&call->mu);
@@ -539,15 +551,28 @@ static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
return (grpc_linked_mdelem *)&md->internal_data;
}
+static grpc_metadata *get_md_elem(grpc_metadata *metadata,
+ grpc_metadata *additional_metadata, int i,
+ int count) {
+ grpc_metadata *res =
+ i < count ? &metadata[i] : &additional_metadata[i - count];
+ GPR_ASSERT(res);
+ return res;
+}
+
static int prepare_application_metadata(grpc_call *call, int count,
grpc_metadata *metadata,
int is_trailing,
- int prepend_extra_metadata) {
+ int prepend_extra_metadata,
+ grpc_metadata *additional_metadata,
+ int additional_metadata_count) {
+ int total_count = count + additional_metadata_count;
int i;
grpc_metadata_batch *batch =
&call->metadata_batch[0 /* is_receiving */][is_trailing];
- for (i = 0; i < count; i++) {
- grpc_metadata *md = &metadata[i];
+ for (i = 0; i < total_count; i++) {
+ const grpc_metadata *md =
+ get_md_elem(metadata, additional_metadata, i, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
l->md = grpc_mdelem_from_string_and_buffer(
@@ -566,9 +591,10 @@ static int prepare_application_metadata(grpc_call *call, int count,
break;
}
}
- if (i != count) {
+ if (i != total_count) {
for (int j = 0; j <= i; j++) {
- grpc_metadata *md = &metadata[j];
+ const grpc_metadata *md =
+ get_md_elem(metadata, additional_metadata, j, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GRPC_MDELEM_UNREF(l->md);
}
@@ -589,24 +615,36 @@ static int prepare_application_metadata(grpc_call *call, int count,
}
}
}
- for (i = 1; i < count; i++) {
- linked_from_md(&metadata[i])->prev = linked_from_md(&metadata[i - 1]);
+ for (i = 1; i < total_count; i++) {
+ grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
+ grpc_metadata *prev_md =
+ get_md_elem(metadata, additional_metadata, i - 1, count);
+ linked_from_md(md)->prev = linked_from_md(prev_md);
}
- for (i = 0; i < count - 1; i++) {
- linked_from_md(&metadata[i])->next = linked_from_md(&metadata[i + 1]);
+ for (i = 0; i < total_count - 1; i++) {
+ grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
+ grpc_metadata *next_md =
+ get_md_elem(metadata, additional_metadata, i + 1, count);
+ linked_from_md(md)->next = linked_from_md(next_md);
}
- switch (prepend_extra_metadata * 2 + (count != 0)) {
+
+ switch (prepend_extra_metadata * 2 + (total_count != 0)) {
case 0:
/* no prepend, no metadata => nothing to do */
batch->list.head = batch->list.tail = NULL;
break;
- case 1:
+ case 1: {
/* metadata, but no prepend */
- batch->list.head = linked_from_md(&metadata[0]);
- batch->list.tail = linked_from_md(&metadata[count - 1]);
+ grpc_metadata *first_md =
+ get_md_elem(metadata, additional_metadata, 0, count);
+ grpc_metadata *last_md =
+ get_md_elem(metadata, additional_metadata, total_count - 1, count);
+ batch->list.head = linked_from_md(first_md);
+ batch->list.tail = linked_from_md(last_md);
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
break;
+ }
case 2:
/* prepend, but no md */
batch->list.head = &call->send_extra_metadata[0];
@@ -615,17 +653,22 @@ static int prepare_application_metadata(grpc_call *call, int count,
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
break;
- case 3:
+ case 3: {
/* prepend AND md */
+ grpc_metadata *first_md =
+ get_md_elem(metadata, additional_metadata, 0, count);
+ grpc_metadata *last_md =
+ get_md_elem(metadata, additional_metadata, total_count - 1, count);
batch->list.head = &call->send_extra_metadata[0];
call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
- linked_from_md(&metadata[0]);
- linked_from_md(&metadata[0])->prev =
+ linked_from_md(first_md);
+ linked_from_md(first_md)->prev =
&call->send_extra_metadata[call->send_extra_metadata_count - 1];
- batch->list.tail = linked_from_md(&metadata[count - 1]);
+ batch->list.tail = linked_from_md(last_md);
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
break;
+ }
default:
GPR_UNREACHABLE_CODE(return 0);
}
@@ -694,48 +737,102 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
return r;
}
-typedef struct cancel_closure {
+typedef struct termination_closure {
grpc_closure closure;
grpc_call *call;
grpc_status_code status;
-} cancel_closure;
+ gpr_slice optional_message;
+ grpc_closure *op_closure;
+ enum { TC_CANCEL, TC_CLOSE } type;
+} termination_closure;
-static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
- cancel_closure *cc = ccp;
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, cc->call, "cancel");
- gpr_free(cc);
+static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp, bool success) {
+ termination_closure *tc = tcp;
+ if (tc->type == TC_CANCEL) {
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel");
+ }
+ if (tc->type == TC_CLOSE) {
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close");
+ }
+ gpr_slice_unref(tc->optional_message);
+ if (tc->op_closure != NULL) {
+ grpc_exec_ctx_enqueue(exec_ctx, tc->op_closure, true, NULL);
+ }
+ gpr_free(tc);
}
-static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
+static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, bool success) {
grpc_transport_stream_op op;
- cancel_closure *cc = ccp;
+ termination_closure *tc = tcp;
memset(&op, 0, sizeof(op));
- op.cancel_with_status = cc->status;
+ op.cancel_with_status = tc->status;
/* reuse closure to catch completion */
- grpc_closure_init(&cc->closure, done_cancel, cc);
- op.on_complete = &cc->closure;
- execute_op(exec_ctx, cc->call, &op);
+ grpc_closure_init(&tc->closure, done_termination, tc);
+ op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &op);
+}
+
+static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, bool success) {
+ grpc_transport_stream_op op;
+ termination_closure *tc = tcp;
+ memset(&op, 0, sizeof(op));
+ tc->optional_message = gpr_slice_ref(tc->optional_message);
+ grpc_transport_stream_op_add_close(&op, tc->status, &tc->optional_message);
+ /* reuse closure to catch completion */
+ grpc_closure_init(&tc->closure, done_termination, tc);
+ tc->op_closure = op.on_complete;
+ op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &op);
+}
+
+static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
+ termination_closure *tc) {
+ grpc_mdstr *details = NULL;
+ if (GPR_SLICE_LENGTH(tc->optional_message) > 0) {
+ tc->optional_message = gpr_slice_ref(tc->optional_message);
+ details = grpc_mdstr_from_slice(tc->optional_message);
+ }
+
+ set_status_code(tc->call, STATUS_FROM_API_OVERRIDE, (uint32_t)tc->status);
+ set_status_details(tc->call, STATUS_FROM_API_OVERRIDE, details);
+
+ if (tc->type == TC_CANCEL) {
+ grpc_closure_init(&tc->closure, send_cancel, tc);
+ GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
+ } else if (tc->type == TC_CLOSE) {
+ grpc_closure_init(&tc->closure, send_close, tc);
+ GRPC_CALL_INTERNAL_REF(tc->call, "close");
+ }
+ grpc_exec_ctx_enqueue(exec_ctx, &tc->closure, true, NULL);
+ return GRPC_CALL_OK;
}
static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description) {
- grpc_mdstr *details =
- description ? grpc_mdstr_from_string(description) : NULL;
- cancel_closure *cc = gpr_malloc(sizeof(*cc));
-
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(termination_closure));
+ tc->type = TC_CANCEL;
+ tc->call = c;
+ tc->optional_message = gpr_slice_from_copied_string(description);
GPR_ASSERT(status != GRPC_STATUS_OK);
+ tc->status = status;
- set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status);
- set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
+ return terminate_with_status(exec_ctx, tc);
+}
- grpc_closure_init(&cc->closure, send_cancel, cc);
- cc->call = c;
- cc->status = status;
- GRPC_CALL_INTERNAL_REF(c, "cancel");
- grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, true, NULL);
+static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description) {
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(termination_closure));
+ tc->type = TC_CLOSE;
+ tc->call = c;
+ tc->optional_message = gpr_slice_from_copied_string(description);
+ GPR_ASSERT(status != GRPC_STATUS_OK);
+ tc->status = status;
- return GRPC_CALL_OK;
+ return terminate_with_status(exec_ctx, tc);
}
static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
@@ -876,9 +973,9 @@ static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
if (elem == NULL) {
return NULL;
} else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
- GPR_TIMER_BEGIN("compression_algorithm", 0);
- set_compression_algorithm(call, decode_compression(elem));
- GPR_TIMER_END("compression_algorithm", 0);
+ GPR_TIMER_BEGIN("incoming_compression_algorithm", 0);
+ set_incoming_compression_algorithm(call, decode_compression(elem));
+ GPR_TIMER_END("incoming_compression_algorithm", 0);
return NULL;
} else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
@@ -1041,9 +1138,9 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
} else {
call->test_only_last_message_flags = call->receiving_stream->flags;
if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
- (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
+ (call->incoming_compression_algorithm > GRPC_COMPRESS_NONE)) {
*call->receiving_buffer = grpc_raw_compressed_byte_buffer_create(
- NULL, 0, call->compression_algorithm);
+ NULL, 0, call->incoming_compression_algorithm);
} else {
*call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
}
@@ -1071,6 +1168,56 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
}
}
+static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
+ batch_control *bctl) {
+ grpc_call *call = bctl->call;
+ /* validate call->incoming_compression_algorithm */
+ if (call->incoming_compression_algorithm != GRPC_COMPRESS_NONE) {
+ const grpc_compression_algorithm algo =
+ call->incoming_compression_algorithm;
+ char *error_msg = NULL;
+ const grpc_compression_options compression_options =
+ grpc_channel_compression_options(call->channel);
+ /* check if algorithm is known */
+ if (algo >= GRPC_COMPRESS_ALGORITHMS_COUNT) {
+ gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
+ algo);
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ } else if (grpc_compression_options_is_algorithm_enabled(
+ &compression_options, algo) == 0) {
+ /* check if algorithm is supported by current channel config */
+ char *algo_name;
+ grpc_compression_algorithm_name(algo, &algo_name);
+ gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
+ algo_name);
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ } else {
+ call->incoming_compression_algorithm = algo;
+ }
+ gpr_free(error_msg);
+ }
+
+ /* make sure the received grpc-encoding is amongst the ones listed in
+ * grpc-accept-encoding */
+ GPR_ASSERT(call->encodings_accepted_by_peer != 0);
+ if (!GPR_BITGET(call->encodings_accepted_by_peer,
+ call->incoming_compression_algorithm)) {
+ extern int grpc_compression_trace;
+ if (grpc_compression_trace) {
+ char *algo_name;
+ grpc_compression_algorithm_name(call->incoming_compression_algorithm,
+ &algo_name);
+ gpr_log(GPR_ERROR,
+ "Compression algorithm (grpc-encoding = '%s') not present in "
+ "the bitset of accepted encodings (grpc-accept-encodings: "
+ "'0x%x')",
+ algo_name, call->encodings_accepted_by_peer);
+ }
+ }
+}
+
static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
void *bctlp, bool success) {
batch_control *bctl = bctlp;
@@ -1085,24 +1232,10 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
grpc_metadata_batch_filter(md, recv_initial_filter, call);
- /* make sure the received grpc-encoding is amongst the ones listed in
- * grpc-accept-encoding */
-
- GPR_ASSERT(call->encodings_accepted_by_peer != 0);
- if (!GPR_BITGET(call->encodings_accepted_by_peer,
- call->compression_algorithm)) {
- extern int grpc_compression_trace;
- if (grpc_compression_trace) {
- char *algo_name;
- grpc_compression_algorithm_name(call->compression_algorithm,
- &algo_name);
- gpr_log(GPR_ERROR,
- "Compression algorithm (grpc-encoding = '%s') not present in "
- "the bitset of accepted encodings (grpc-accept-encodings: "
- "'0x%x')",
- algo_name, call->encodings_accepted_by_peer);
- }
- }
+ GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
+ validate_filtered_metadata(exec_ctx, bctl);
+ GPR_TIMER_END("validate_filtered_metadata", 0);
+
if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
0 &&
!call->is_client) {
@@ -1245,7 +1378,40 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- if (op->data.send_initial_metadata.count > INT_MAX) {
+ /* process compression level */
+ grpc_metadata compression_md;
+ memset(&compression_md, 0, sizeof(grpc_metadata));
+ size_t additional_metadata_count = 0;
+ grpc_compression_level effective_compression_level;
+ bool level_set = false;
+ if (op->data.send_initial_metadata.maybe_compression_level.is_set) {
+ effective_compression_level =
+ op->data.send_initial_metadata.maybe_compression_level.level;
+ level_set = true;
+ } else {
+ const grpc_compression_options copts =
+ grpc_channel_compression_options(call->channel);
+ level_set = copts.default_level.is_set;
+ if (level_set) {
+ effective_compression_level = copts.default_level.level;
+ }
+ }
+ if (level_set && !call->is_client) {
+ const grpc_compression_algorithm calgo =
+ compression_algorithm_for_level_locked(
+ call, effective_compression_level);
+ char *calgo_name;
+ grpc_compression_algorithm_name(calgo, &calgo_name);
+ // the following will be picked up by the compress filter and used as
+ // the call's compression algorithm.
+ compression_md.key = GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY;
+ compression_md.value = calgo_name;
+ compression_md.value_length = strlen(calgo_name);
+ additional_metadata_count++;
+ }
+
+ if (op->data.send_initial_metadata.count + additional_metadata_count >
+ INT_MAX) {
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
@@ -1253,7 +1419,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->sent_initial_metadata = 1;
if (!prepare_application_metadata(
call, (int)op->data.send_initial_metadata.count,
- op->data.send_initial_metadata.metadata, 0, call->is_client)) {
+ op->data.send_initial_metadata.metadata, 0, call->is_client,
+ &compression_md, (int)additional_metadata_count)) {
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
@@ -1341,7 +1508,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (!prepare_application_metadata(
call,
(int)op->data.send_status_from_server.trailing_metadata_count,
- op->data.send_status_from_server.trailing_metadata, 1, 1)) {
+ op->data.send_status_from_server.trailing_metadata, 1, 1, NULL,
+ 0)) {
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
@@ -1530,9 +1698,10 @@ uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; }
grpc_compression_algorithm grpc_call_compression_for_level(
grpc_call *call, grpc_compression_level level) {
gpr_mu_lock(&call->mu);
- const uint32_t accepted_encodings = call->encodings_accepted_by_peer;
+ grpc_compression_algorithm algo =
+ compression_algorithm_for_level_locked(call, level);
gpr_mu_unlock(&call->mu);
- return grpc_compression_algorithm_for_level(level, accepted_encodings);
+ return algo;
}
const char *grpc_call_error_to_string(grpc_call_error error) {
diff --git a/src/core/lib/surface/call_log_batch.c b/src/core/lib/surface/call_log_batch.c
index a6d1d5149f..31c074f15d 100644
--- a/src/core/lib/surface/call_log_batch.c
+++ b/src/core/lib/surface/call_log_batch.c
@@ -112,7 +112,7 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
size_t i;
for (i = 0; i < nops; i++) {
tmp = grpc_op_string(&ops[i]);
- gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
+ gpr_log(file, line, severity, "ops[%" PRIuPTR "]: %s", i, tmp);
gpr_free(tmp);
}
}
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index a7ea6fa1f0..f0b3c2e15d 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -36,16 +36,17 @@
#include <stdlib.h>
#include <string.h>
+#include <grpc/compression.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
-#include "src/core/lib/surface/init.h"
#include "src/core/lib/transport/static_metadata.h"
/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
@@ -64,10 +65,12 @@ typedef struct registered_call {
struct grpc_channel {
int is_client;
uint32_t max_message_length;
+ grpc_compression_options compression_options;
grpc_mdelem *default_authority;
gpr_mu registered_call_mu;
registered_call *registered_calls;
+
char *target;
};
@@ -111,6 +114,7 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
channel->registered_calls = NULL;
channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
+ grpc_compression_options_init(&channel->compression_options);
if (args) {
for (size_t i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
@@ -151,6 +155,27 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
":authority", args->args[i].value.string);
}
}
+ } else if (0 == strcmp(args->args[i].key,
+ GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
+ channel->compression_options.default_level.is_set = true;
+ GPR_ASSERT(args->args[i].value.integer >= 0 &&
+ args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT);
+ channel->compression_options.default_level.level =
+ (grpc_compression_level)args->args[i].value.integer;
+ } else if (0 == strcmp(args->args[i].key,
+ GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
+ channel->compression_options.default_algorithm.is_set = true;
+ GPR_ASSERT(args->args[i].value.integer >= 0 &&
+ args->args[i].value.integer <
+ GRPC_COMPRESS_ALGORITHMS_COUNT);
+ channel->compression_options.default_algorithm.algorithm =
+ (grpc_compression_algorithm)args->args[i].value.integer;
+ } else if (0 ==
+ strcmp(args->args[i].key,
+ GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
+ channel->compression_options.enabled_algorithms_bitset =
+ (uint32_t)args->args[i].value.integer |
+ 0x1; /* always support no compression */
}
}
grpc_channel_args_destroy(args);
@@ -324,6 +349,11 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
+grpc_compression_options grpc_channel_compression_options(
+ const grpc_channel *channel) {
+ return channel->compression_options;
+}
+
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index ff3debc31f..7eff7b8883 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -76,4 +76,8 @@ void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_channel_internal_unref(exec_ctx, channel)
#endif
+/** Return the channel's compression options. */
+grpc_compression_options grpc_channel_compression_options(
+ const grpc_channel *channel);
+
#endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_H */
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index 79de54beb5..0677f29766 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -235,7 +235,7 @@ void grpc_mdctx_global_shutdown(void) {
gc_mdtab(shard);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
- gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
+ gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked",
shard->count);
if (grpc_iomgr_abort_on_leaks()) {
abort();
@@ -248,7 +248,7 @@ void grpc_mdctx_global_shutdown(void) {
gpr_mu_destroy(&shard->mu);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
- gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
+ gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
shard->count);
for (size_t j = 0; j < shard->capacity; j++) {
for (internal_string *s = shard->strs[j]; s; s = s->bucket_next) {